Select Certain Entries From A ListThe other day we were working with computed for display fields and one had to display all the entries from a hidden multi-value field that did not start with a fixed string. For example, the multi-value field could have entries that were "flagged" by starting with "***" and we wanted to hide those values in a computed for display field. (The multi-value field content was controlled by administrators, so we needed a way to hide the ones that they signaled out by starting them with three asterisks).
While looking through the ND6 help, someone noticed the @Transform function. Hmm, seemed promising. But this formula was going to be running on the client in a mixed R5/ND6 environment. So a function introduced in ND6 wouldn't work. We had to come up with an R5 solution.
After coming up with the R5 solution, we decided to spend some time to see how this would be done in a pure ND6 environment. It was surprisingly easy in ND6. The re-write of the formula language to allow looping (@Transform has its own built-in looping) makes things far easier to write. So here we show both solutions.
You'll want to create a form in your ND6 designer to show off both solutions. First, create an editable text field called SourceList. Set it up to allow multiple values, and give it a default value of:
"One" : "Two" : "Three" : "Four" : "Five" : "Six" : "Seven" : "Eight" : "Nine" : "Ten"
Next, create another editable text field called RemoveChar. This field does not allow multiple values. This will be the "flag". Entries from SourceList that start with this character (or characters, if you want) will not be shown in our display fields to come. Set this field up to have a default value of "T".
Next, create a hidden editable text field that allows multiple values. This field will hold the overall results. This is just used to demonstrate the technique - in "real life" you probably wouldn't use an editable field like this. Call this field Results and don't put in any default value.
Finally, set up a computed for display text field that allows multiple values called D_Results. The formula for this field should be Results.
OK, now create two buttons. The first button computes everything using only R5 code. The second button computes everything using ND6 code. Label the buttons however you want, and set each of them up to run formula language. Here's the code for the R5 button:
FIELD Results := Results;
StartOfList := @Left(SourceList; @Length(RemoveChar));
RestOfList := @RightBack(SourceList; @Length(RemoveChar));
NewList := @Replace(StartOfList; RemoveChar; "~") + RestOfList;
OnesToRemove := @Trim(@Replace(SourceList; NewList; ""));
OnesToKeep := @Trim(@Replace(SourceList; OnesToRemove; ""));
Some of these lines could be consolidated, but this code will be a little easier to describe. First, we need to initialize the Results field so we can use @SetField later on. (Yes, there are other ways to do this).
The variable StartOfList gives us a list where every element has the first "n" characters from the corresponding position in SourceList. The value "n" is based on how long your RemoveChar value is. Using the default values assigned to the fields, StartOfList ends up like this:
"O" : "T" : "T" : "F" : "F" : "S" : "S" : "E" : "N" : "T"
The variable RestOfList ignores the first "n" characters and keeps the rest from each element of SourceList. (That's how @RightBack works). So, again using the default values, RestOfList ends up like this:
"ne" : "wo" : "hree" : "our" : "ive" : "ix" : "even" : "ight" : "ine" : "en"
The variable NewList takes StartOfList, replaces the elements that exactly match what we want to remove and replaces it with a tilde character. (Note that if the starting character you want to remove is a tilde, you would need to put something different into the formula). @Replace works on every element in the list. So we have a new list that will be added to RestOfList. The new list (before adding to RestOfList) is:
"O" : "~" : "~" : "F" : "F" : "S" : "S" : "E" : "N" : "~"
After adding it to RestOfList (the + concatentates strings on each element in the list), we end up with this list as a value for NewList:
"One" : "~wo" : "~hree" : "Four" : "Five" : "Six" : "Seven" : "Eight" : "Nine" : "~en"
Notice how "One", "Four", etc. (the ones that don't start with "T") have not been updated, but the others have been updated. So now it's a matter of displaying the ones that were not updated.
The variable OnesToRemove finds the ones in the original list that were not updated and gets rid of them, leaving only the ones from the original list that are different in NewList. So, OnesToRemove looks like this:
"Two" : "Three" : "Ten"
Finally, OnesToKeep takes the original list and wipes out the ones to remove. So we end up with a list of all entries that do not start with our starting character. That list is put into the Results field and the document is refreshed so the computed for display field will show the results.
Wow. In ND6, the formula ends up being two lines, and ones of those is refreshing the document:
FIELD Results := @Transform(SourceList; "x"; @If(@Left(x; @Length(RemoveChar)) = RemoveChar; @Nothing; x));
The @Transform function loops through all members of a list, applies a formula, and puts the results of the formula back into that same position in the list. You pass in the list to process as the first parameter. The second parameter is a string. This is a forward reference into the formula. The value for each position, as the list is being processed, will be put into this variable. Here, it is called "x". So, any references to "x" in the formula will be replaced by the actual list values as the list is being processed.
The third parameter is the formula to apply. Whatever the result of the formula is, it will be put back into the list at the same position. If you use the keyword @Nothing, then that position of the list will not exist - it will automatically be trimmed out at the end. So, here we see if the first "n" characters of the value match the character(s) to be removed. If they match, then the element is removed. If they don't match, the element is untouched.
So, in one line of code we process every element in the list, check to see if the first character(s) of the element match the character(s) to be removed, and then either remove the element or keep it. The resulting list is put into the Results field. Then the document is refreshed as before.
Check out the form in your ND6 client. The two formulas end up doing the exact same thing, but the ND6 version is a whole lot easier to follow. If you're in a complete R5 environment or a mixed R5/ND6 environment, then the first formula is your only choice. But when you move to a complete ND6 environment, you should take a look at the new looping capabilities in formula language to make your code shorter and easier to support.