mikke89 / RmlUi

RmlUi - The HTML/CSS User Interface library evolved
https://mikke89.github.io/RmlUiDoc/
MIT License
2.87k stars 312 forks source link

For `input` elements, `change` event callback happens before data model is updated? #668

Open AmaiKinono opened 2 months ago

AmaiKinono commented 2 months ago

I've created an example in the tutorial directory. Here are the important bits:

index.rml:

<rml>
<head>
    <link type="text/css" href="index.rcss"/>
    <title>Window</title>
</head>
<body data-model="data">
    <input type="text" data-value="text" data-event-change="print_self"></input>
</body>
</rml>

main.cpp:

// ...
#include <iostream>

Rml::String text;

void print_text(Rml::DataModelHandle, Rml::Event&, const Rml::VariantList&)
{
  std::cout << text << "\n";
}

bool SetupDataBinding(Rml::Context* context, Rml::DataModelHandle& model)
{
  Rml::DataModelConstructor ctor = context->CreateDataModel("data");
  if (!ctor) {
    return false;
  }
  model = ctor.GetModelHandle();
  ctor.Bind("text", &text);
  ctor.BindEventCallback("print_self", &print_text);
  return true;
}

// ... in main function

    Rml::Debugger::Initialise(context);
    Shell::LoadFonts();

    Rml::DataModelHandle model_handle;
    SetupDataBinding(context, model_handle);

// ...

If we run this in a terminal:

The same is tested on select element and the behavior is similar.

So it seems the callback is called before data model is updated. What should I do if I need the updated data in such callback?

Thanks!

mikke89 commented 2 months ago

Right, so both of these data controllers effectively add an event listener for the change event. I believe in whichever order they are declared, or actually it might be a bit arbitrary due to unordered maps being involved. And then they just do their thing in that order when the change event is emitted.

For the data views, we are being a lot more comprehensive to give everything a defined update order. However, I believe we don't really do anything like this for the data controllers (value and event). For controllers, I guess it makes more sense to define an initialization order, rather than an update order.

So yeah, I think it makes sense to always initialize the value controller first, so that it gets to the event first. At least I can't really think of any downsides.

AmaiKinono commented 2 months ago

Thanks for the explanation. I'd like to talk a bit about the background. I'm trying to complete the 7 GUIs challenge using RmlUi, and the following use cases requires to update the value first:

And I didn't found a use case that requires to update the value after a data-event-x callback in this challenge.

mikke89 commented 1 month ago

Oh, interesting. Haven't come across this project before. Definitely some interesting challenges.

I am fully on board with making this change, the use cases here are convincing to me.

mikke89 commented 3 weeks ago

For reference, here's an old comment describing essentially the same issue, and also a note that data-checked does the expected thing as opposed to data-value (but we should still make the order specified in all of these cases): https://github.com/mikke89/RmlUi/issues/482#issuecomment-1848772051