docs(ivy): document breaking change with <select> and binding order (#34709)
Closes #34470 PR Close #34709
This commit is contained in:
parent
6315acae94
commit
9c5510b28e
|
@ -229,3 +229,66 @@ export class BaseMenu {
|
||||||
@Directive({selector: '[settingsMenu]'})
|
@Directive({selector: '[settingsMenu]'})
|
||||||
export class SettingsMenu extends BaseMenu {}
|
export class SettingsMenu extends BaseMenu {}
|
||||||
```
|
```
|
||||||
|
|
||||||
|
{@a select-value-binding}
|
||||||
|
## Cannot Bind to `value` property of `<select>` with `*ngFor`
|
||||||
|
|
||||||
|
|
||||||
|
### Basic example of change
|
||||||
|
|
||||||
|
|
||||||
|
```html
|
||||||
|
<select [value]="someValue">
|
||||||
|
<option *ngFor="let option of options" [value]="option"> {{ option }} <option>
|
||||||
|
</select>
|
||||||
|
```
|
||||||
|
|
||||||
|
In the View Engine runtime, the above code would set the initial value of the `<select>` as expected.
|
||||||
|
In Ivy, the initial value would not be set at all in this case.
|
||||||
|
|
||||||
|
|
||||||
|
### Background
|
||||||
|
|
||||||
|
Prior to Ivy, directive input bindings were always executed in their own change detection pass before any DOM bindings were processed.
|
||||||
|
This was an implementation detail that supported the use case in question:
|
||||||
|
|
||||||
|
```html
|
||||||
|
<select [value]="someValue">
|
||||||
|
<option *ngFor="let option of options" [value]="option"> {{ option }} <option>
|
||||||
|
</select>
|
||||||
|
```
|
||||||
|
|
||||||
|
It happened to work because the `*ngFor` would be checked first, during the directive input binding pass, and thus create the options first.
|
||||||
|
Then the DOM binding pass would run, which would check the `value` binding.
|
||||||
|
At this time, it would be able to match the value against one of the existing options, and set the value of the `<select>` element in the DOM to display that option.
|
||||||
|
|
||||||
|
In Ivy, bindings are checked in the order they are defined in the template, regardless of whether they are directive input bindings or DOM bindings.
|
||||||
|
This change makes change detection easier to reason about for debugging purposes, since bindings will be checked in depth-first order as declared in the template.
|
||||||
|
|
||||||
|
In this case, it means that the `value` binding will be checked before the `*ngFor` is checked, as it is declared above the `*ngFor` in the template.
|
||||||
|
Consequently, the value of the `<select>` element will be set before any options are created, and it won't be able to match and display the correct option in the DOM.
|
||||||
|
|
||||||
|
### Example of error
|
||||||
|
|
||||||
|
There is no error thrown, but the `<select>` in question will not have the correct initial value displayed in the DOM.
|
||||||
|
|
||||||
|
|
||||||
|
### Recommended fix
|
||||||
|
|
||||||
|
To fix this problem, we recommend binding to the `selected` property on the `<option>` instead of the `value` on the `<select>`.
|
||||||
|
|
||||||
|
*Before*
|
||||||
|
```html
|
||||||
|
<select [value]="someValue">
|
||||||
|
<option *ngFor="let option of options" [value]="option"> {{ option }} <option>
|
||||||
|
</select>
|
||||||
|
```
|
||||||
|
|
||||||
|
*After*
|
||||||
|
```html
|
||||||
|
<select>
|
||||||
|
<option *ngFor="let option of options" [value]="option" [selected]="someValue == option">
|
||||||
|
{{ option }}
|
||||||
|
<option>
|
||||||
|
</select>
|
||||||
|
```
|
|
@ -61,3 +61,5 @@ If the errors are gone, switch back to Ivy by removing the changes to the `tscon
|
||||||
* `DebugElement.attributes` returns `undefined` for attributes that were added and then subsequently removed (previously, attributes added and later removed would have a value of `null`).
|
* `DebugElement.attributes` returns `undefined` for attributes that were added and then subsequently removed (previously, attributes added and later removed would have a value of `null`).
|
||||||
|
|
||||||
* `DebugElement.classes` returns `undefined` for classes that were added and then subsequently removed (previously, classes added and later removed would have a value of `false`).
|
* `DebugElement.classes` returns `undefined` for classes that were added and then subsequently removed (previously, classes added and later removed would have a value of `false`).
|
||||||
|
|
||||||
|
* If selecting the native `<option>` element in a `<select>` where the `<option>`s are created via `*ngFor`, use the `[selected]` property of an `<option>` instead of binding to the `[value]` property of the `<select>` element (previously, you could bind to either.) [details](guide/ivy-compatibility-examples#select-value-binding)
|
Loading…
Reference in New Issue