SAP / ui5-webcomponents

UI5 Web Components - the enterprise-flavored sugar on top of native APIs! Build SAP Fiori user interfaces with the technology of your choice.
https://sap.github.io/ui5-webcomponents/
Apache License 2.0
1.51k stars 263 forks source link

[ ui5-select | Any | v1.21.2 ]: Select component value cannot be set if options not available yet #8174

Open vasicvuk opened 8 months ago

vasicvuk commented 8 months ago

Bug Description

The method for setting value works by selecting the option from this list like this:

https://github.com/SAP/ui5-webcomponents/blob/main/packages/main/src/Select.ts#L498

In case we are loading the options async, and setting a value before that, the first option is selected rather than the real value.

I tried to find some event when the options are changed so i can change the value then, but didn't find such event.

Affected Component

Select

Expected Behaviour

The value should be considered even if the option does not exists.

Isolated Example

No response

Steps to Reproduce

No response

Log Output, Stack Trace or Screenshots

No response

Priority

None

UI5 Web Components Version

v1.21.2

Browser

Edge

Operating System

Windows

Additional Context

No response

Organization

No response

Declaration

LidiyaGeorgieva commented 8 months ago

Hello @vasicvuk ,

Please provide reproducible example of your issue. This is one codesanbox sample, created by us. You can extend it.

Regards, Lidiya

vasicvuk commented 8 months ago

Hi @LidiyaGeorgieva Here is the reproduction:

https://codesandbox.io/p/sandbox/ui5-webcomponents-forked-xkt62t?file=%2Findex.html%3A2%2C17

Options are loaded with setTimeout to simulate API Requests, value was set before that because we have value immediately but ignored because there were no select options.

ilhan007 commented 8 months ago

Hello @vasicvuk

the Select's value is a bit unique in terms of how it works. While all properties of components cause invalidation of the components and are part of the component's state, the Select's value only proxies to the Options. The Options store the selection state (via Option#selected). Otherwise, we will end up with state in the Select and state in the Options and that will complicate the logic as constant synchronisation between these two states will be required.

So, what you observe is kind of expected - there are no options available, the Select's value can't set the selected property to an Option. In other words, Select's value works only synchronously. Select's value is useful in more straightforward use-cases. Although technically we can address this, we don't really want to, because we would like to keep the selection state only at one place.

In your use-case, with the Options coming later-on, I suggest you opt for setting the selection trough the Option#selected property.

I hope it's won't be that inconvenient.

Best Regards, ilhan

vasicvuk commented 8 months ago

Hi @ilhan007

This is very inconvenient because in most cases the selected value comes from another data source, than the available options. Available options are usually some dictionaries and the values from the real objects. In this way, we cannot do parallel API calls just because of how Select works.

In frameworks such as Angular, we use [(ngModel)] or "formControl" binding, and since this works over the Value property, it would just remove the value from the bound model.

ilhan007 commented 8 months ago

Hello @vasicvuk isn't possible to perform the selection, after you get the options, I assume you have a hook once the API call completes and the options arrive

ilhan007 commented 8 months ago

In addition, in frameworks such as Angular, to be able to use [(ngModel)] or "formControl" binding we have another project https://github.com/SAP/ui5-webcomponents-ngx. It's a wrapper library around our web components for better integration with Angular. Are using the pure UI5 Web Components directly in Angular? And do you use them in Reactive forms as you mentioned?

vasicvuk commented 8 months ago

Hello @vasicvuk isn't possible to perform the selection after you get the options, I assume you have a hook once the API call completes and the options arrive

This is not possible, as the rendering of option items is not done in the same period as you set the items to list, so if I set the items to list and then value, still ui5-option will not be rendered because *ngFor is not yet executed and DOM is not updated yet.

vasicvuk commented 8 months ago

In addition, in frameworks such as Angular, to be able to use [(ngModel)] or "formControl" binding we have another project https://github.com/SAP/ui5-webcomponents-ngx. It's a wrapper library around our web components for better integration with Angular. Are using the pure UI5 Web Components directly in Angular? Do you use them in Reactive forms as you mentioned?

As I see in Angular you are just writing the value directly on Host which will cause the same problem:

https://github.com/SAP/ui5-webcomponents-ngx/blob/main/libs/angular-generator/src/lib/ui5-webcomponents/generic-cva.ts#L84

I am currently not using this library, because i have my own component wrappers for this and then Angular bindings on top of that.

ilhan007 commented 8 months ago

In addition, in frameworks such as Angular, to be able to use [(ngModel)] or "formControl" binding we have another project https://github.com/SAP/ui5-webcomponents-ngx. It's a wrapper library around our web components for better integration with Angular. Are using the pure UI5 Web Components directly in Angular? Do you use them in Reactive forms as you mentioned?

As I see in Angular you are just writing the value directly on Host which will cause the same problem:

https://github.com/SAP/ui5-webcomponents-ngx/blob/main/libs/angular-generator/src/lib/ui5-webcomponents/generic-cva.ts#L84

I am currently not using this library, because i have my own component wrappers for this and then Angular bindings on top of that.

I mentioned the ngx wrapper project for your reference - just in case. As long as you have your own wrappers, handling the Angular specifics things - it's ok.

ilhan007 commented 8 months ago

Hello @vasicvuk isn't possible to perform the selection after you get the options, I assume you have a hook once the API call completes and the options arrive

This is not possible, as the rendering of option items is not done in the same period as you set the items to list, so if I set the items to list and then value, still ui5-option will not be rendered because *ngFor is not yet executed and DOM is not updated yet.

Can't you set the selection on the options themselves via the selected property, then it should be fine.

vasicvuk commented 8 months ago

Hello @vasicvuk isn't possible to perform the selection after you get the options, I assume you have a hook once the API call completes and the options arrive

This is not possible, as the rendering of option items is not done in the same period as you set the items to list, so if I set the items to list and then value, still ui5-option will not be rendered because *ngFor is not yet executed and DOM is not updated yet.

Can't you set the selection on the options themselves via the selected property, then it should be fine.

I can mix the information from two data sources, but as I said this is inconvenient, as I would have to wait for a data source for options to load to show all information. This slows done the rendering for no reason. Additionally, I cannot set any info into my model until all the options are loaded.

ilhan007 commented 8 months ago

Probably not optimal, sorry for the inconvenience. However, I am not sure that anything is slowed down, as you are nevertheless waiting for the options, it's just that you have to set the selection along with them using the Option#selected property. Case 1: If the data source for the options come second - use the result from the first data source (that defines the selected value) to set the respective Option's selected property Case 2: If the data source for the options comes first, you nevertheless should wait for the first data source (that defines the selected value) and then Select's value would work

You described Case 1 as problematic, and the suggestion, while not optimal and the most convenient, is to use the result from the first data source (that defines the selected value) to set the respective Option's selected property. Would that be acceptable?

vasicvuk commented 8 months ago

It is not acceptable because I am rendering my options with for loop in framework and model on data source does not have the selected as attribute, which means I have to also have a seperate model and mapping for each select I am having in the app.

It is possible to do, and I am doing so right now but as I said it is very inconvenient.