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…
	
	
			
			x
			
			
		
	
		Reference in New Issue
	
	Block a user