A client had sent me an email asking for some quick help coding a HotDocs generated report that would list cases by attorney. The question was how to get a page break when the attorney changed. Easy, I say. Test whether the current attorney in the list is different than the last one, if it is, insert the page break. The first attempt at the code looked something like this:
<<REPEAT Cases and Attorneys>>
[Text of the report]
<<IF (COUNTER > 1) AND (Attorney Name != Attorney Name[COUNTER –1 ]>>
[Page Break]
<<END IF>>
<<END REPEAT>>
This code appears to do the job and will run through the list and test whether the Attorney Name in the current loop is different from the Attorney Name in the previous (i.e. COUNTER – 1) loop. However, there is a latent flaw in this code that appears if there is a sort or a filter function applied to the REPEAT. In this particular case, the list needed to be sorted by Attorney Name so that all the cases with the same attorney would print together. To find the defect, you have to know a little more about how REPEATing dialogs work.
There are two ways to access information in a REPEATing dialog.
REPEATing dialogs work like dynamic arrays. Every entry is given a sequential index and can be accessed in two different ways, in an REPEAT/END REPEAT block and through direct indexing. For example, assume I have a repeating list of attorneys, and I enter “Moe”, “Larry”, “Curley”, and “Shemp” into the list.
The normal way to access the list of names is through a REPEAT/END REPEAT block. This code in the document:
<<REPEAT Attorneys>>
<<Attorney Name>>
<<END REPEAT>>
will produce the list:
Moe
Larry
Curly
Shemp
The second way to access the list of names is by specifying which the name you want directly by using an index:
Attorney Name[1] = “Moe”
Attorney Name[2] = “Larry”
Attorney Name[3] = “Curley”
Attorney Name[4] = “Shemp”
So this HotDocs code in the template:
The Attorney is <<Attorney[3]>>
will result with this:
The Attorney is Curley
when the document is assembled. No REPEAT command needed.
Finding the latent error in the original code.
Looking back at the original code, the statement
Attorney Name != Attorney Name[COUNTER –1 ]
in the REPEAT/END REPEAT block should test whether the current Attorney Name is not equal to the name from the previous loop through the REPEAT/END REPEAT block; i.e. the COUNTER – 1 value. This works when using a REPEAT command without a sort or filter because the built in COUNTER variable will match the index of the variable result. So this code:
<<REPEAT Attorney Names>><<Attorney Name>><<END REPEAT>>
will loop through 4 times, and what happens behind the scenes is this:
Loop1: COUNTER = 1, Attorney Name = “Moe” which is Attorney Name[1]
Loop2: COUNTER = 2, Attorney Name = “Larry” which is Attorney Name[2]
Loop3: COUNTER = 3, Attorney Name = “Curley” which is Attorney Name[3]
Loop4: COUNTER = 4, Attorney Name = “Shemp” which is Attorney Name[4]
and it works because Attorney Name[COUNTER – 1] will always produce the Attorney Name from the previous loop.
However, the COUNTER will not match the variable index when the same REPEAT is filtered or sorted. So if the REPEAT sorts alphabetically:
<<REPEAT Attorney Names::>Attorney Name>><<Attorney Name>><<END REPEAT>>
this is what happens behind the scenes:
AlphaSortLoop1: COUNTER = 1, Attorney Name = “Curley” which is Attorney Name[3]
AlphaSortLoop2: COUNTER = 2, Attorney Name = “Larry” which is Attorney Name[2]
AlphaSortLoop3: COUNTER = 3, Attorney Name = “Moe” which is Attorney Name[1]
AlphaSortLoop4: COUNTER = 4, Attorney Name = “Shemp” which is Attorney Name[4]
This was the latent flaw in the original code. The test:
Attorney Name != Attorney Name[COUNTER –1]
works only if the COUNTER is the same as the index because then Attorney Name[COUNTER – 1] will output the Attorney Name from the previous loop. However, with a sort or filter on the REPEAT the test is not guaranteed to work. In the alphabetically sorted example above, I want the variables in the test to check if the current name equals the prior name, i.e. for AlphaSortLoop2 the test should be:
“Larry” != “Curley”
However, COUNTER = 2 for AlphaSortLoop2, therefore Attorney Name[COUNTER –1] = Attorney Name[2 – 1] = Attorney Name[1] = “Moe” instead. This makes the test condition work like this instead:
“Larry” != “Moe”
which is not the correct test.
The solution to this particular problem is just to add another variable, and not rely on the index and direct addressing of the variable. So creating a separate “Prior Attorney Name” variable fixes the latent defect. The corrected code reads like this:
<<REPEAT Cases and Attorneys>>
[Text of the report]
<<IF (COUNTER > 1) AND (Attorney Name != Prior Attorney Name)>>
[Page Break]
<<END IF>>
<<SET Prior Attorney Name TO Attorney Name>>
<<END REPEAT>>
Now the report will run correctly regardless of whether there is a filter or sort applied.