Last time out, DTML Basics demonstrated conditional statements. This time around, it's time to study loops...which, in the DTML world, aren't exactly what you're used to. Take a look.
This is fairly simple - after starting a HTML table to display the details, I've
invoked the GetUsers() ZSQL Method. The difference is that, this time, I've added two attributes: the "size" attribute, which specifies the number of items in each batch (6), and the "start" attribute, which specifies the sequence number of the first item in the batch.
Remember that sequence items are numbered from 1. As a result, the first batch contains items numbered 1 to 6, the second 7 to 12, and so on. In this example, I will need to constantly change the value of the "start" attribute so that results are displayed correctly. That's why I've stored this value in a variable called "start_here" - this variable will constantly be updated, as demonstrated in the code snippet below:
This bit of code controls of the display of the "Previous 6 users" link that
appears at the top of the listing. It first checks the value of the "sequence-start" variable to ensure that it is at the top of the current batch of records - this helps to ensure that the link only appears at the top of the listing.
Next, it checks the value of the "sequence-previous" variable. This is a special variable that is true if the current batch is not the first batch of a sequence. However, this is only true for the first iteration of the loop - for the subsequent items of the current batch, this value is again false. As a result, the link is displayed only once for the current batch.
The "URL" variable stores the URL to the DTML Method, while the "sequence-query" variable stores the query string. However, this does not contain the "start_here" variable - this variable is added dynamically via the "previous-sequence-start-number" variable (as the name of the variable suggests, this stores the starting sequence number of the previous batch.) This value is assigned to the "start_here" variable, which in turn sets the value for the "start" attribute of the <dtml-in> tag. Finally, the "previous-sequence-size" variable is used to display the number of items in the previous batch.
Looks familiar? It should - it's almost the same code you saw earlier...except
that, this time, it's used to display a "Next 6 users" link.
The first thing to do here is to check the value of the "sequence-end" variable. This is true if the current element is the last element of the sequence and, in our the case, the current batch. This helps to ensure that the link only appears at the end of the listing.
The "sequence-next" variable is a special variable that is true if the current batch is not the last batch of a sequence. Once again, this is only true for the first iteration of the loop. Next, we have the "URL" and "sequence-query" variables that provide the same functionality again - an absolute URL to our query method.
The "next-sequence-start-number" variable comes next - this stores the starting number of the next batch. Again, this value is assigned to the "start_here" variable, and the "next-sequence-size" variable is used to display the number of items in the next batch.
That was heavy, wasn't it? But understanding it is worth the effort - this kind of code is reusable, and, once you've figured it out, you'll find it useful in more than one place. Again, Zope proves the value of object reusability, and demonstrates how easy it is to implement complicated widgets with just a few lines of code.
And that's about it for the moment. In this article, I explained how sequences work, and demonstrated how they could be processed with DTML. In the Zope world, a sequence need not consist of just variables; it can just as easily contain objects, and it comes with a number of special properties. This makes it possible to build some fairly powerful widgets with just a few lines of code - this article demonstrated a directory viewer and a pager - and also eases the task of writing simple, maintainable code.
In the next article in this series, I'll be looking at a couple of other constructs that may come in useful in your journey through DTML. Come back next week for more.
Note: All examples in this article have been tested on Linux/i586 with Zope 2.5.0. Examples are illustrative only, and are not meant for a production environment. Melonfire provides no warranties or support for the source code described in this article. YMMV!