Local Variables in Reusable Interface

Certified Associate Developer

Hi!

I created an interface with cardChoiceField, which allows me to choose one of multiple subinterfaces (via rule!), which I created before. These subinterfaces have a dropdown which value is assigned to a local (to subinterface) variable. 

The problem is that when I choose a value in the dropdown it doesn't change the local variable simultaneously - to see the "refreshed" interface, I have to switch to other subinterface, and then turn back to the original. In that case I obtain the subinterface I want, with refreshed variables. Is there any way to do this without switching to other subinterfaces? 

I understand that it could be solved using rule inputs, but I would like to know how the interaction with local variables in reusable interfaces work

  Discussion posts and replies are publicly visible

Parents Reply Children
  • 0
    Certified Associate Developer
    in reply to Harshit Bumb (Appyzie)

    I think I'm not allowed to post the original code, so I created an example with the same type of problem

    Here is the parent:

    a!localVariables(
      local!link: null(),
      {
        a!cardChoiceField(
          label: "Select A Version",
          data: {
            a!map(id: rule!IM_Child1(), icon: "globe-alt", primaryText: "Text"),
            a!map(id: rule!IM_Child2(), icon: "globe-europe", primaryText: "Num")
          },
          cardTemplate: a!cardTemplateBarTextStacked(
            id: fv!data.id,
            primaryText: fv!data.primaryText,
            icon: fv!data.icon,
            iconColor: "POSITIVE"
          ),
          saveInto: {local!link},
          maxSelections: 1,
          validations: {}
        ),
        a!sectionLayout(
          label: "",
          contents: local!link
        )
      })

    Here is child 1:

    a!localVariables(
      local!var:{"text1", "text2", "text3"},
      local!res:null,
      {
      a!dropdownField(
        label: "Dropdown",
        labelPosition: "ABOVE",
        placeholder: "--- Select a Value ---",
        choiceLabels: local!var,
        choiceValues: local!var,
        value: local!res,
        saveInto: {local!res},
        searchDisplay: "AUTO",
        validations: {}
      ),
      a!textField(
        label: "Text",
        value: local!res,
        labelPosition: "ABOVE",
        saveInto: {},
        refreshAfter: "UNFOCUS",
        validations: {},
        showWhen: a!isNotNullOrEmpty(local!res)
      )
    })

    Here is child 2:

    a!localVariables(
      local!var:{"num1", "num2", "num3"},
      local!res:null,
      {
        a!dropdownField(
          label: "Dropdown",
          labelPosition: "ABOVE",
          placeholder: "--- Select a Value ---",
          choiceLabels: local!var,
          choiceValues: local!var,
          value: local!res,
          saveInto: {local!res},
          searchDisplay: "AUTO",
          validations: {}
        ),
        a!textField(
          label: "Text",
          value: local!res,
          labelPosition: "ABOVE",
          saveInto: {},
          refreshAfter: "UNFOCUS",
          validations: {},
          showWhen: a!isNotNullOrEmpty(local!res)
        )
      })

    To recreate the problem you have to:

    1. Select "Text" choice.

    2. Choose any value in dropdown.

    3. See nothing has changed.

    4. Switch to "Num" choice.

    5. Switch back to "Text" choice.

    6. At this point I obtain the "Text" interface with refreshed variable.

  • Your child interfaces need to actually save their values up into the parent interface.  I'm not altogether clear what you're doing in this example exactly, but it's pretty clear to me that no value ever gets saved from the child to the parent.  In both of your child interface examples here the local variables are scoped such that they'd only be accessible locally.

    There's not some sort of "magic" that makes data in a child interface automatically promote up to a parent interface, you actually have to build that into your structure.

  • 0
    Certified Lead Developer
    in reply to vladislavm9556

    I thin the issue here is, that you put the output of the called child interfaces into the id field of your maps. These will when behave in a static way. I suggest to just pass references to these interfaces to the id field but omitting the brackets. The evaluate the child interfaces like this:

    contents: local!link()

    Check out my recent blog article for more details: https://appian.rocks/2022/09/19/building-customisable-components/

  • 0
    Certified Associate Developer
    in reply to Stefan Helzle

    If I understood you correctly, the idea was to restructure the code in this manner:

    a!localVariables(
      local!link: null,
      {
        a!cardChoiceField(
          label: "Select A Version",
          data: {
            a!map(id: rule!IM_Child1, icon: "globe-alt", primaryText: "Text"),
            a!map(id: rule!IM_Child2, icon: "globe-europe", primaryText: "Num")
          },
          cardTemplate: a!cardTemplateBarTextStacked(
            id: fv!data.id,
            primaryText: fv!data.primaryText,
            icon: fv!data.icon,
            iconColor: "POSITIVE"
          ),
          saveInto: {local!link},
          maxSelections: 1,
          validations: {}
        ),
        a!sectionLayout(
          label: "",
          contents: local!link()
        )
      })

    but it gives me the following error: 

    Could not display interface. Please check definition and inputs. Interface Definition: Expression evaluation error at function local!link [line 22]: The function 'link' is unavailable.

  • IMHO you're way over-complicating this.  Your parent need only save a marker / pointer of whichever child you currently want to show, instead of trying to save the child itself into some sort of local variable.

    a!localVariables(
      /*local!link: null,*/
      local!selection: null(),
    
      {
        a!cardChoiceField(
          label: "Select A Version",
          data: {
            a!map(
              /*id: rule!IM_Child1,*/
              id: 1,
              icon: "globe-alt",
              primaryText: "Text"
            ),
            a!map(
              /*id: rule!IM_Child2,*/
              id: 2,
              icon: "globe-europe",
              primaryText: "Num"
            )
          },
          cardTemplate: a!cardTemplateBarTextStacked(
            id: fv!data.id,
            primaryText: fv!data.primaryText,
            icon: fv!data.icon,
            iconColor: "POSITIVE"
          ),
          saveInto: 
          /*{*/
            /*local!link*/
            local!selection,
          /*},*/
          value: local!selection,
          maxSelections: 1,
          validations: {}
        ),
        a!sectionLayout(
          label: "Selected...",
          contents: {
            a!match(
              value: index(local!selection, 1, null()),
              equals: 1,
              then: a!boxLayout(label: "rule!IM_child1 would go here"),
              equals: 2,
              then: a!boxLayout(label: "rule!IM_child2 would go here"),
              
              default: {}
            )
          }
        )
      }
    )