Permutation Comparison In Hide FormulasEvery once in a while you "re-learn" things in Notes that you haven't used in a while. One of those I recently went through was permutation comparisons in formula language. When working on a recent application, there were several types of users: Global Readers, Global Editors, Administrators, and Developers. Each had their own role in the database: [GloReader], [GloEditor], [Admin], and [Developer]. I wanted to have an action button in the "main" view that only people in one of the roles would see. If they had any (one or more) of the roles enabled, they could see the button. If they had no roles enabled, they could not see the button.
I could have handled this through process. For example, I could have said that if you have the [GloEditor] role enabled, then you must have the [GloReader] role, and if you have the [Admin] role you must have the [GloEditor] role, and if you have the [Developer] role you must have the [Admin] role. If I forced that process, then the action button would only have to check for the [GloReader] role, because that is the "building block" for the other roles. But I didn't want to necessarily force that process.
So, I had to check for all the roles. In my first pass, I checked each role individually and gathered the results in a hide formula that looked like this:
@IsNotMember("[GloReader]"; @UserRoles) & @IsNotMember("[GloEditor]"; @UserRoles) & @IsNotMember("[Admin]"; @UserRoles) & @IsNotMember("[Developer]"; @UserRoles)
That hide formula works fine, but it just seemed to me that it was a bit overkill. There had to be a "cooler" way. So I looked more into @IsNotMember. According to the help, If both parameters are lists, returns 1 if all elements of textListValue1 are not contained in textListValue2. So I tried this:
@IsNotMember("[GloReader]" : "[GloEditor]" : "[Admin]" : "[Developer]"; @UserRoles)
This works, but it's difficult to explain. @UserRoles is going to be an empty string, or a list of one or more of the four values. If it's an empty string, then everything in the first parameter (the hard-code role names) are not in the 2nd parameter (nothing is in the 2nd parameter), and the formula returns 1 (@True) so the line is hidden. If the 2nd parameter has one or more roles in it, then there is a match between some element in first list and some element in the second list, so the formula returns 0 (@False) and the line is shown.
You can also use permutation comparison. In formula language, this is indicated by *=. (If you used just = with two lists, then Notes will compare pair-wise - the first element in the 1st list against the first element in the 2nd list and so on). The way a permutation comparison works, Notes will return 1 if any of the pairs match up. So a statement like this:
"[GloReader]" : "[GloEditor]" : "[Admin]" : "[Developer]" *= @UserRoles
will return 1 if any of the pairs match up. This means that if there are any of those roles in the user's list of roles, the line will be hidden (the formula will return 1). You have to global "not" the whole statement to get exactly what we want (show the line if there are any of the roles).
You might think that you could use *!= instead of putting a "not" around the whole line. That actually doesn't work. Since it's a permutation comparison, it checks the first entry in the first list with every entry in the second list, and so on. One of those comparisons will be not equal, so the whole statement will always return 1 (@True). Let's say the user has "[Admin]" as their only role. Comparing "[GloReader]" and "[Admin]", they are not equal, so the whole statement returns 1.
I ended up using @IsNotMember with the list. My thought was that it would be a bit easier to support and understand later on, even if I wasn't the one supporting this application later on.