Dynamic Page updates - which value was changed?

It's very late - I know I'll regret asking this later but..

I have a dynamic page that is generated with many input fields on it each of which uses a (code generated) dynamic variable input name eg var0 var1 var2 etc.

When the user updates an input field on that page the page automatically closes as they click out of the entry and the setting[varX] value is updated as expected. What I need to know is which settings[varX] was updated though so I can onwardly populate that value elsewhere. How can I do that ? I can't see where to run code immediately after the update has happened.

Code at the start of the dynamic page does immediately run after the update but I can't get that variable name there it seems...

help...

I now think my problem is not as described above...

What I think is happening is that the user updates an input and I then try and read back from settings[varX] what that input value was but I'm getting the previous value not the new value. I guess this is a 'state' type situation where it hasn't been updated through the system yet.

I will have to further think how to avoid this before the page is displayed again. Maybe I can write the variable name to a @Field static and read it back slightly later.. if I can ascertain which input is being updated .... hmmm

update.. @Field statics set within the dynamic page do not update :frowning: but it appears atomicState vars might work for me..

No - it's still eluding me ..

How do I know the name of the input field that the user clicked in and changed ?
The dynamic page closes immediately once they have done this

... or can I execute some code somewhere once the user does that click and before the page closes?

I'm looking for the same thing. Did you even figure out an answer?

I do it like this: @Field static volatileState = [:].asSynchronized()

And then I write a getter and setter for entries in that Map. It works 100% reliably for me.

FWIW, I have used preferences inputs in the app page in many cases for referencing data between dynamic page refreshes and it has seemed to be reliable, but I was always concerned about timing issues because their implementation and caching behaviors are pretty opaque.

I haven't seen a meaningful difference between state and atomicState for a use case like this. Both are sort of slow and unpredictable.

You can also use buttons, which @arnb educated me on recently. If you have a button press that is required to initiate your action, you know specifically which one was pressed.

You declare them like this, and they submit the dynamicPage when pressed.

input(name: "importProntoCodes", type: "button", title: "Press to import entered codes")

Then you need a handler like this:

void appButtonHandler(btn)
{
    // btn is string name of the button input
}

In the app that I posted here, I declare the button inputs on the dynamicPage, and I use appButtonhandler to set a flag in my @Field Static Map.

Then in the code that executes in my dynamicPage I check whether the entry is set in the Map, and if so I do the action that the button press was supposed to initiate, then I clear the entry from the Map.

What's the purpose of volatileState in @Field? You can do all of this with simple state variables.

Also, with other input types, using submitOnChange: true, you can simply test that the input was set. If it was, one option is to put its value into state, and clear the input.

Dynamic pages aren't so dynamic as to require any kind of synchronization, as they are driven solely by user inputs, one at a time.

Anecdotally I have chased plenty of bugs that feel like the result of racing against caching and storage behaviors in the internal implementation. Especially when things like asynchronous or concurrent accesses come into play. You certainly know more about its implementation and have more data to consider than I do.

Nothing beats State for ease of use, but I do it this way when I need it to work no matter what.

None of the built-in apps use this for user interactions, and none of them have problems with caching or storage behaviors. Having said that, there have on occasion been such problems, but those were bugs since fixed in the platform. The UI is pretty straight forward at this point, without hidden gremlins.

Philosophically, I don't ever want to have to code around bugs in the platform. Those bugs have to be identified and fixed.

1 Like

The solution I came to was simply to set a flag using a state variable and then have a function executed on each refresh of the main page that does whatever needs doing. A little kludgy but it works.

I do set singleThreaded to true to eliminate multithreaded artifacts when dealing with state variables which I experienced in my early drivers.

1 Like

Not really kludgy at all. This is a standard method to deal with dynamic pages. This, and testing that an input with submitOnChange: true became set and acting on that.

My coding experience is an event driven model where you might have an onSubmit() or onChange() method for each control. So that was my point of comparison. In my app I had 5 or 6 controls and thus 5 or 6 flags and that was why it felt untidy relative to my prior perspective.

Download the Hubitat app