Reg Exp
Web Design
Notes Client
Multi-Column Display Field
Recently I was working on an application and had a need to show information in multiple columns to save screen space. The source field was going to contain somewhere around 30 items, but the exact number was unknown. And the values to display we're short, either. Although I'm not at liberty to say exactly what the values were, a good example would be capitals for each of the United States of America. The user would pick somewhere around 30 state capitals and the values would be shown.

If all the elements are displayed with commas (or semicolons) separating the values, then you save screen space but it becomes difficult to read. It's easier to read the elements when they are on their own lines. But having 30 or so elements, each on its own line, wastes a lot of screen space. A good compromise is to use multiple columns to show the data. For example, if you have three columns of information, you can show 1/3 of the data in each column. Then you get both benefits - screen space is saved, and the elements are easier to read.

First, you need a table with three columns and one row. The border of the table can be hidden (up to you). This will be where the values will be displayed. This table should be hidden in edit mode and shown in read mode. The actual field where the user chooses the values should be hidden in read mode and shown in edit mode.

Inside each table cell is computed text. You could use a computed for display field, but that is not necessary. I personally like to use computed text whenever possible - one benefit is that you can put the computed text in pass through HTML and the HTML will be applied on the Notes client and the web - if you use a computed for display field and put it in pass through HTML the HTML will only be applied on the web. The key is that the computed text figures out how much of the field to display, then displays that subset with a new line separator.

For this example, we are working with 3 columns. So each field should display 1/3 of the values. If the number of elements is evenly divisible by 3 (let's say there are 33 elements) then each column has the same number of elements (11 in this case). But if the number of elements is not divisible by 3, then the columns will not have the same number of elements. For 34 elements, the first column should have 12 and the second and third columns should have 11. For 35 elements, the first and second columns should have 12, and the third should have 11. We use a function called @Modulo to determine if we have a value that is evenly divisible or not.

The big key is finding the starting and ending points for each field. For the first field, the starting point is 1 (the first element). The ending point is "one third" of the number of elements:

OneThird := @If(@Modulo(@Elements(Cities); 3) = 1; (@Elements(Cities)+2)/3; @Modulo(@Elements(Cities); 3) = 2; (@Elements(Cities)+1)/3; @Elements(Cities)/3);

Note that Cities is the name of the field that we're displaying. We check to see the remainder of the number of elements divided by 3. If the remainder is 1, then this column (this is the first column) will have one more value than the other two columns. By adding 2 to the number of elements then dividing by 3, we get an even number with the number of values to show in the first column. For example, if there are 34 elements, then 34+2 = 36, and 36 / 3 = 12, so there are 12 elements to show in the first column.

If the number of elements divided by 3 gives us a remainder of 2, then this first column also shows an extra value (so does the second column). But to compute that even value we add 1 this time. For example, if there are 35 elements, 35+1 = 36, and 36 / 3 = 12.

The only other choice is that the number of elements divided by 3 gives us a 0 remainder (it's evenly divided). In that case, each column is going to have an equal number of values, so we divide by 3 to get that number of elements to show.

Now that we have the OneThird value computed, we know where to start and end our array of values. It starts at 1 and ends at the value just computed. So we can grab that subset and display those values with a new line separator:

List := @Subset(Cities; OneThird);
@Implode(List; @NewLine)

The second computed text value is a little more complicated. We compute the variable OneThird in exactly the same way as before. But we need to know where to stop. So I have a variable called TwoThirds that is computed:

TwoThirds := @If(@Modulo(@Elements(Cities); 3) = 1; OneThird + (OneThird-1); OneThird + OneThird);

If the number of elements divided by 3 gives a remainder of 1, then this column (the second column) is showing the same amount as the third column, which is one less than the first column. For example, for 35 elements, then OneThird is 12, and we want to show 11 in the second column, so the stopping number is 23. If the number of elements divided by 3 gives a remainder of either 0 or 2, then the second column shows the same number of elements as the first column, so the stopping point is double the OneThird value.

Next, we generate a subset of just the values to show in the second column, and display those values:

List := @Subset(@Subset(Cities; TwoThirds); (OneThird-TwoThirds));
@Implode(List; @NewLine)

Two subsets are used here. The first one grabs the first TwoThirds elements. The second pulls out the LAST values to show. (The first group is shown in the first column). OneThird minus TwoThirds will always give a negative number. And the number will be the difference between the two, so that's how many values to show in the second column.

For the third column, again we use the variables OneThird and TwoThirds, just like in the second column. This time the computed text pulls out the last value from the list (only the ones that haven't been shown) and displays those:

List := @Subset(Cities; TwoThirds-@Elements(Cities));
@Implode(List; @NewLine)

The second parameter to @Subset will again be a negative number, and will be the number of elements not shown in either of the first two columns.

So, that's it. One thing I should point out, though. The @Subset formula doesn't like the second parameter to be 0. So, if there is any chance at all that there will be less than 3 elements, then you should implement a check. For example, the first line of the computed text for the second column will be:

Check := @If(@Elements(Cities) < 2; @Return(""); 0);

So, instead of erring out, the formula simply exits with a null string value.

If you want to have more or less columns, the flow should be the same. For example, with four columns you would have variables of OneQuarter, OneHalf, and ThreeQuarters. (Obviously, you could call them whatever you want, but you get the idea).