hybridsjs / hybrids

Extraordinary JavaScript UI framework with unique declarative and functional architecture
https://hybrids.js.org
MIT License
3.03k stars 85 forks source link

Cannot define default nested model #226

Closed Qsppl closed 9 months ago

Qsppl commented 9 months ago

I have a form to create a new user.

The User has a 'status' property and by default the Draft User model is created with the 'status' property value set to 'null'.

image

But the value of the 'status' property cannot be 'null'. The value of the 'status' property can be one of the status models:

{id: 1, ...} / {id: 2, ...} / {id: 3, ...} / {id: 4, ...}.

Default status: {id: 1, ...}.

I can't set the default value to the desired model, so I have to manually set the value to "1" instead of 'null' in the element - so unless the user has manually selected an option, the Draft remains 'null'.

image

And now I need to set the default value again, now in store.submit()

image

This is repeated for each field in which an enumerated model can be selected. There are a lot of models with such fields. If it were possible to define a default model, it would be very convenient and the code would become clearer.

smalluban commented 9 months ago

If the nested model is external (has an id, or defined storage), then the root model keeps the reference, which in moment of the definition can't be known (nested models are just defined there, or used, not fetched). The default value for that relation must be null. The definition of the model defines a structure, and it is not supposed to fetch anything.

What you can do, is when your form component connects (the best place would be an observe method), set up the relation for the draft (set the default) - then is it possible to fetch the nested model, and it's the right place to do so.

{
  draft: {
    ...store(Model, { draft: true }),
    observe(host, model, lastModel) {
      // only fires for the first initial get, or when model id changes (clear draft, or submit)
      if (!lastModel || model.id !== lastModel.id) {
        store.set(model, { nestedModel: host.myExternalNestedModel })
      }
    },
  },
}

The other option is to have that default in the set() method of the model storage if it is not overwritten by the user. In the UI you can set a default for the select element if the nested model is not set.

Qsppl commented 9 months ago

Thanks, this solved the problem.

smalluban commented 9 months ago

By the way, the store.ref() is only useful for self reference or for avoiding ES module cycle imports. Otherwise it does not do anything.