Controling bindings evaluation order

Yes, in the code updateA and updateB would be some type of flag.

I think I found a way...

dropA: Bound to params.family_id
dropB: expression binding:

if (isNull(dropA.value),
    null,
    params.category_id
)

dropC: expression binding:

if (isNull(dropB.value),
  null,
  params.item_id
)

There's a slight delay, but... it works. And it handles both the initial setup and the reset.
I'll test it a bit more but it might be enough...

Try this:

View JSON
{
  "custom": {
    "isFresh": true
  },
  "params": {
    "category_id": "",
    "family_id": "",
    "item_id": ""
  },
  "propConfig": {
    "custom.isFresh": {
      "access": "PRIVATE",
      "binding": {
        "config": {
          "expression": "coalesce({view.params.family_id}, {view.params.category_id}, {view.params.item_id})"
        },
        "transforms": [
          {
            "expression": "true",
            "type": "expression"
          }
        ],
        "type": "expr"
      },
      "persistent": true
    },
    "params.category_id": {
      "paramDirection": "input",
      "persistent": true
    },
    "params.family_id": {
      "paramDirection": "input",
      "persistent": true
    },
    "params.item_id": {
      "onChange": {
        "enabled": null,
        "script": "\tself.getChild(\"root\").getChild(\"families\").getChild(\"Dropdown\").props.value \u003d self.params.family_id\n\tself.getChild(\"root\").getChild(\"categories\").getChild(\"Dropdown\").props.value \u003d self.params.category_id\n\tself.getChild(\"root\").getChild(\"items\").getChild(\"Dropdown\").props.value \u003d self.params.item_id"
      },
      "paramDirection": "input",
      "persistent": true
    }
  },
  "props": {},
  "root": {
    "children": [
      {
        "children": [
          {
            "events": {
              "component": {
                "onActionPerformed": {
                  "config": {
                    "params": {},
                    "view": "Pascal2"
                  },
                  "scope": "C",
                  "type": "nav"
                }
              }
            },
            "meta": {
              "name": "Button"
            },
            "position": {
              "basis": "80px"
            },
            "props": {
              "text": "Return"
            },
            "type": "ia.input.button"
          },
          {
            "meta": {
              "name": "Label"
            },
            "position": {
              "basis": "100px"
            },
            "propConfig": {
              "props.text": {
                "binding": {
                  "config": {
                    "path": "view.custom.isFresh"
                  },
                  "type": "property"
                }
              }
            },
            "type": "ia.display.label"
          }
        ],
        "meta": {
          "name": "return"
        },
        "position": {
          "basis": "50px"
        },
        "type": "ia.container.flex"
      },
      {
        "children": [
          {
            "meta": {
              "name": "Label"
            },
            "position": {
              "basis": "150px"
            },
            "props": {
              "text": "families"
            },
            "type": "ia.display.label"
          },
          {
            "meta": {
              "name": "Dropdown"
            },
            "position": {
              "basis": "256px"
            },
            "propConfig": {
              "props.options": {
                "binding": {
                  "config": {
                    "queryPath": "sandbox/list_families"
                  },
                  "type": "query"
                }
              },
              "props.value": {
                "binding": {
                  "config": {
                    "expression": "if(true, {view.params.family_id}, {this.props.options})"
                  },
                  "transforms": [
                    {
                      "code": "\treturn value if self.view.custom.isFresh else None",
                      "type": "script"
                    }
                  ],
                  "type": "expr"
                },
                "onChange": {
                  "enabled": null,
                  "script": "\tif origin \u003d\u003d \u0027Browser\u0027:\n\t\tself.view.custom.isFresh \u003d False"
                }
              }
            },
            "props": {
              "showClearIcon": true
            },
            "type": "ia.input.dropdown"
          },
          {
            "meta": {
              "name": "value"
            },
            "position": {
              "basis": "150px"
            },
            "propConfig": {
              "props.text": {
                "binding": {
                  "config": {
                    "path": "../Dropdown.props.value"
                  },
                  "type": "property"
                }
              }
            },
            "type": "ia.display.label"
          }
        ],
        "meta": {
          "name": "families"
        },
        "position": {
          "basis": "34px"
        },
        "props": {
          "style": {
            "gap": "3px"
          }
        },
        "type": "ia.container.flex"
      },
      {
        "children": [
          {
            "meta": {
              "name": "Label"
            },
            "position": {
              "basis": "150px"
            },
            "props": {
              "text": "categories"
            },
            "type": "ia.display.label"
          },
          {
            "meta": {
              "name": "Dropdown"
            },
            "position": {
              "basis": "256px"
            },
            "propConfig": {
              "props.options": {
                "binding": {
                  "config": {
                    "parameters": {
                      "family_id": "{.../families/Dropdown.props.value}"
                    },
                    "queryPath": "sandbox/list_categories"
                  },
                  "type": "query"
                }
              },
              "props.value": {
                "binding": {
                  "config": {
                    "expression": "if(true, {view.params.category_id}, {this.props.options})"
                  },
                  "transforms": [
                    {
                      "code": "\treturn value if self.view.custom.isFresh else None",
                      "type": "script"
                    }
                  ],
                  "type": "expr"
                },
                "onChange": {
                  "enabled": null,
                  "script": "\tif origin \u003d\u003d \u0027Browser\u0027:\n\t\tself.view.custom.isFresh \u003d False"
                }
              }
            },
            "props": {
              "showClearIcon": true
            },
            "type": "ia.input.dropdown"
          },
          {
            "meta": {
              "name": "value"
            },
            "position": {
              "basis": "150px"
            },
            "propConfig": {
              "props.text": {
                "binding": {
                  "config": {
                    "path": "../Dropdown.props.value"
                  },
                  "type": "property"
                }
              }
            },
            "type": "ia.display.label"
          }
        ],
        "meta": {
          "name": "categories"
        },
        "position": {
          "basis": "34px"
        },
        "props": {
          "style": {
            "gap": "3px"
          }
        },
        "type": "ia.container.flex"
      },
      {
        "children": [
          {
            "meta": {
              "name": "Label"
            },
            "position": {
              "basis": "150px"
            },
            "props": {
              "text": "items"
            },
            "type": "ia.display.label"
          },
          {
            "meta": {
              "name": "Dropdown"
            },
            "position": {
              "basis": "256px"
            },
            "propConfig": {
              "props.options": {
                "binding": {
                  "config": {
                    "parameters": {
                      "category_id": "{.../categories/Dropdown.props.value}"
                    },
                    "queryPath": "sandbox/list_items"
                  },
                  "type": "query"
                }
              },
              "props.value": {
                "binding": {
                  "config": {
                    "expression": "if(true, {view.params.item_id}, {this.props.options})"
                  },
                  "transforms": [
                    {
                      "code": "\treturn value if self.view.custom.isFresh else None",
                      "type": "script"
                    }
                  ],
                  "type": "expr"
                },
                "onChange": {
                  "enabled": null,
                  "script": "\tif origin \u003d\u003d \u0027Browser\u0027:\n\t\tself.view.custom.isFresh \u003d False"
                }
              }
            },
            "props": {
              "showClearIcon": true
            },
            "type": "ia.input.dropdown"
          },
          {
            "meta": {
              "name": "value"
            },
            "position": {
              "basis": "150px"
            },
            "propConfig": {
              "props.text": {
                "binding": {
                  "config": {
                    "path": "../Dropdown.props.value"
                  },
                  "type": "property"
                }
              }
            },
            "type": "ia.display.label"
          }
        ],
        "meta": {
          "name": "items"
        },
        "position": {
          "basis": "34px"
        },
        "props": {
          "style": {
            "gap": "3px"
          }
        },
        "type": "ia.container.flex"
      }
    ],
    "meta": {
      "name": "root"
    },
    "props": {
      "direction": "column",
      "style": {
        "gap": "10px",
        "padding": "15px"
      }
    },
    "type": "ia.container.flex"
  }
}

The only scripts are very simple transforms that check the semaphore. The use of coalesce() with the custom.isFresh view property is solely to have something that will respond to parameter changes.

Similarly, the if(true, ...) expressions for the dropdowns' props.value is there purely to monitor changes to the options.

{ You'll have to reset the nav target to the your real project's view name. }

1 Like

Thanks.
I just tried it and I get the same slight delay.
Can you see a reason to use one solution over the other ?

Your solution is not monitoring the options for when the queries deliver the lists.

Why is this a problem ?
edit: Yep found it.

edit again: What if I just put a property change script on dropA and dropB options ?
Or would it be better to hack an options monitoring into my expressions ?

I strongly prefer bindings over change scripts--usually easier to follow, and they make it hard to forget a return case.

And you need to monitor the options prop on all three dropdowns.

The third one is actually a special case that I handle differently, as changes can happen to them that shouldn't trigger a reset.

1 Like

I would remove all bindings from B and C, then update them with a scripted on Change on A and B.

How would that work to give them their initial value ?

how about instead of reseting the values of your dropdown in an onchange script, you reset them in an on action performened event on the dropdowns A and B

3 Likes

I guess it would work. I'll give it a shot, see if it makes things simpler.

That might be the best solution so far, it's simple and integrates well with some other requirements I have.

Now why the hell didn't anyone think of this sooner ?

1 Like

when the crazy js wizard finds a simple solution... xd

1 Like

Curios, how would I take the JSON here and create a component with it? It's not a simple copy and paste is it? Nope, that didn't work.

Shift-right-click on a view in the designer tree, then paste. Must be an entire view.