Modeling a Computation Rule that needs to reference its own field path

I have a modelling problem that I can’t figure out how to solve in the Kernel Language. The problem sounds simple, but I run into a cyclic dependency when I try to solve it.

I have a Repeatable Group with Fields VALUE, NAME and EXCLUDE. VALUE is an enum with the values “unused”, “v1”, “v2” and “v3”. NAME and EXCLUDE are text fields. I want a Rule that sets VALUE to “unsused” whenever VALUE of another group instance is set to something other than “unused” and EXCLUDE of the other group instance equals NAME of this group instance. So basically, each group instance can “deactivate” another group instance, when it has a value other than “unused” set.

The problem is that I can’t have a computation for a field with its field path used in the computation. Otherwise I could just set VALUE to “unused”directly when the condition is met. As a workaround I tried to compute a confirm helper field like this:

Precondition: AtLeastOneFieldValueIncludedInValueList(MyGroup*/VALUE Having [EXCLUDE] == [$NAME] And
CurrentRepetition(RuleGroup) != CurrentRepetition($RuleGroup)
In “v1”, “v2”, “v3”)
Calculation: True

But I can’t do much with this helper field, since setting VALUE as a dependent field on it also leads to a cyclic dependency. Another workaround I tried is adding a new Field VALUE_INPUT and use this field in the computation above. Then if the condition becomes true, I set VALUE_INPUT to not relevant/read only and VALUE to “unused”. Otherwise I set VALUE to the value of VALUE_INPUT.

This seems to work at first, but runs into problems when I have chains of exclusions. If I have the Group Instances A, B and C, where A excludes B and B excludes C and all values are set to “unused”. Then I set B to “v1” which excludes C. Then I set A to “v1”. This leads to B being excluded but C also being excluded, as I did not change VALUE_INPUT of B, but only VALUE.

Do you have an idea how I can solve my problem?

Hi @jonas-flat-ash

We’re firmly in workaround territory here.

That being said, there are still some options available to you before you turn to custom code. The attached models end up with this:

1. Use a manual trigger
Similar to the discussion in Make inline-repeat line readonly after saving you could use a manual trigger. A validation rule can be used to check when the Manual Trigger is not set and then a dependency can set the VALUE to “unused”

GroupFilled(RuleGroup)
And FieldValueIncludedInValueList(VALUE, "v1", "v2", "v3")
And AtLeastOneFieldValueIncludedInValueList(../MyGroup*/VALUE Having [EXCLUDE]
    == [$NAME]
    And CurrentRepetition(RuleGroup) != CurrentRepetition($RuleGroup) In "v1", "v2", "v3")
And FieldNotFilled(MANUAL_TRIGGER)

2. Use Two Fields
Similar to the discussion in Computed fields readonly even with unfulfilled precondition you can use two fields. This is like you have suggested in your answer but the difference is that this second field does not trigger anything, it is simply displayed under a certain set of conditions.

3. Use Filter Expressions
Similar to the discussion in Filter Expression for repeats based on FieldFilled you can use filter expressions to specify which data is shown. As @tim-deep-thread points out, you should be aware that:

Proposed Solution

  1. Model two repeats and use Filter Expressions as suggested in 3.
  2. Set the Filter Expression, [VALUE_TRIGGER] = "false" for the active rows based on the inverse Precondition
NoFieldValueIncludedInValueList(../MyGroup*/VALUE Having [EXCLUDE] == [$NAME] And
CurrentRepetition(RuleGroup) != CurrentRepetition($RuleGroup)
In "v1", "v2", "v3")
  1. Set the Filter Expression [VALUE_TRIGGER] = "true"for the deactivated rows using the Precondition that you proposed.
AtLeastOneFieldValueIncludedInValueList(../MyGroup*/VALUE Having [EXCLUDE] == [$NAME] And
CurrentRepetition(RuleGroup) != CurrentRepetition($RuleGroup)
In "v1", "v2", "v3")
  1. Visualize the Computed Value as suggested in 2.

This leads to the rows being automatically deactivated. However, deactivated rows can also deactivate other (newer) rows. It’s not clear if this is desired or not. You can adapt VALUE_TRIGGERComp to something like CurrentRepetition(RuleGroup) > CurrentRepetition($RuleGroup) to restrict the deactivation to deactivation by newer rows.

Equally, switching to the manual trigger approach would also allow you to set VALUE == "unused" and then also reference this in the Rules as I have done in the attached models which leads to an extension to your precondition:

(FieldValueIncludedInValueList(VALUE, "v1", "v2", "v3")
And AtLeastOneFieldValueIncludedInValueList(../MyGroup*/VALUE Having [EXCLUDE]
    == [$NAME]
    And CurrentRepetition(RuleGroup) != CurrentRepetition($RuleGroup) In "v1", "v2", "v3"))
OR [VALUE] == "unused"

2024.06-ext6 models
CompRuleReferencesOwnPath_DM.json (10.8 KB)
CompRuleReferencesOwnPath_FM.json (5.0 KB)

FYI The fact that cyclic dependencies are not supported is documented here.

Hi @malcolm-silver-ice, thank you for your detailed solution :slight_smile:
Unfortunately I don’t think that it quite fulfills the requirements given to me. In the documents you sent, all rows with the value of VALUE_COPY set to “unused” are hidden in the “Active Values Group” table. This is (sadly) not quite what I need.

There are two cases for rows with VALUE_COPY set to “unused” (as I understand it, VALUE_COPY is the “true” value and VALUE is used as user input only).

  1. The first case is that a row is excluded by another row. This should lead to the excluded row still being visible, but the user input for VALUE_COPY (which is the VALUE dropdown in your solution) should be hidden (which I did in my solutions by setting it to not relevant). Also, the value of VALUE_COPY must be set to “unused”. The rest of the row does not need to be set to readonly as in our case all other columns are readonly anyway.
  2. The second case is that a row has VALUE_COPY set to “unused” by the user (by using the VALUE dropdown). This should have no effect on the row at all.

If I understand it correctly, your solution handled both cases the same by hiding a row with VALUE_COPY set to “unused” through a filter expression. However this doesn’t satisfy any of the above cases. I made some adaptions to your solution to fit the cases above better, but is seems to fall back to the solution I had previously where exclusion chains break the logik. The changes I did:

  • Remove the filter expression
  • Set VALUE_INPUT as a dependent field on VALUE_TRIGGER, where it is set to “not relevant” when VALUE_TRIGGER is “true”.
  • Removed the MANUAL_TRIGGER column as I don’t think it is relevant in my case?
  • For the VALUE_TRIGGERComp Computation, removed the computation for False
  • For the VALUE_TRIGGERComp Computation, reduced the computation for True to
    AtLeastOneFieldValueIncludedInValueList(../MyGroup*/VALUE Having [EXCLUDE] == [$NAME] And CurrentRepetition(RuleGroup) != CurrentRepetition($RuleGroup) In “v1”, “v2”, “v3”)"

I added some screenshots and the model files to show the behaviour. Thanks for your solution again and sorry if my previous explanation was ambiguous.

(In the last image I would expect the C row to be usable again, as the row that excludes it is itself excluded)

CompRuleReferencesOwnPath_FM.json (4.8 KB)

CompRuleReferencesOwnPath_DM.json (10.3 KB)

Hi,

Yes, I would expect C to be excluded based on the fact that row 2 (NAME = B, EXCLUDE = C) excludes it. I tried to highlight this when I said:

You want to perform an addition check to see if

AtLeastOneFieldValueIncludedInValueList(../MyGroup*/VALUE Having [EXCLUDE] == [$NAME]
    And CurrentRepetition(RuleGroup) != CurrentRepetition($RuleGroup)
In "v1", "v2", "v3")

is true due to a row where VALUE itself is excluded.

This is the case in your final screenshot where the “C” row is excluded by the “B” row which itself is excluded by the “A” row.

Whilst you cannot

Nor can you nest Language Constructs to have something like:

AtLeastOneFieldValueIncludedInValueList(../MyGroup*/VALUE Having [EXCLUDE] == [$NAME]
    And CurrentRepetition(RuleGroup) != CurrentRepetition($RuleGroup)
    And NoFieldValueIncludedInValueList(<check if this row is already excluded>)
In "v1", "v2", "v3")

You can model another Computed Field and reference this:

AtLeastOneFieldValueIncludedInValueList(../MyGroup*/VALUE Having [EXCLUDE] == [$NAME]
    And CurrentRepetition(RuleGroup) != CurrentRepetition($RuleGroup)
    And FieldFilled(ISEXCLUDED)
In "v1", "v2", "v3")

I’ve added this to the models and it seems to answer your use-case now. However, as the VALUE field data is unchanged, when the “C” row is reactivated, the previous VALUE value is shown (not “unused”
CompRuleReferencesOwnPath_DM_v3.json (10.8 KB)
CompRuleReferencesOwnPath_FM_v3.json (5.0 KB)

Note on Performance

  1. There are a maximum of 10 rows in the example repeat
  2. The new ISEXCLUDEDComp iterates through every row and checks it against every other row until it finds something
  3. This leads to a potential 10^2 checks
  4. This value must be evaluated before VALUE_TRIGGERComp can be evaluated
  5. VALUE_TRIGGERComp iterates through every row and checks it against every other row until it finds something
  6. As a result you might be iterating through this repeat 10^4 times.

:warning: Increasing the number of repetitions in the repeat could lead to performance problems.

Hi, thanks again for your detailed solution!

Unfortunately this solution also runs into problems with longer dependency chains. We have now decided to not support dependency chains in our project instead of trying to find an even more complex solution.

Thank you again for your effort :slight_smile: