mirror of
https://github.com/angular/angular.git
synced 2026-09-14 13:54:52 +08:00
fix(form): set select value after option renders (#63340)
This commit is contained in:
@@ -7,6 +7,7 @@
|
||||
*/
|
||||
|
||||
import {
|
||||
afterNextRender,
|
||||
computed,
|
||||
DestroyRef,
|
||||
Directive,
|
||||
@@ -177,9 +178,11 @@ export class Control<T> {
|
||||
input: HTMLInputElement | HTMLTextAreaElement | HTMLSelectElement,
|
||||
): void {
|
||||
const inputType =
|
||||
input instanceof HTMLTextAreaElement || input instanceof HTMLSelectElement
|
||||
input instanceof HTMLTextAreaElement
|
||||
? 'text'
|
||||
: input.type;
|
||||
: input instanceof HTMLSelectElement
|
||||
? 'select'
|
||||
: input.type;
|
||||
|
||||
input.addEventListener('input', () => {
|
||||
switch (inputType) {
|
||||
@@ -227,6 +230,15 @@ export class Control<T> {
|
||||
},
|
||||
);
|
||||
break;
|
||||
case 'select':
|
||||
this.maybeSynchronize(
|
||||
() => this.state().value(),
|
||||
(value) => {
|
||||
// A select will not take a value unil the value's option has rendered.
|
||||
afterNextRender(() => (input.value = value as string), {injector: this.injector});
|
||||
},
|
||||
);
|
||||
break;
|
||||
default:
|
||||
this.maybeSynchronize(
|
||||
() => this.state().value(),
|
||||
|
||||
@@ -22,6 +22,7 @@ import {
|
||||
Control,
|
||||
disabled,
|
||||
form,
|
||||
hidden,
|
||||
max,
|
||||
MAX,
|
||||
maxLength,
|
||||
@@ -196,6 +197,35 @@ describe('control directive', () => {
|
||||
expect(cmp.f().value()).toBe('two');
|
||||
});
|
||||
|
||||
it('should assign correct value when unhiding select', () => {
|
||||
@Component({
|
||||
imports: [Control],
|
||||
template: `
|
||||
@if (!f().hidden()) {
|
||||
<select #select [control]="f">
|
||||
@for(opt of options; track opt) {
|
||||
<option [value]="opt">{{opt}}</option>
|
||||
}
|
||||
</select>
|
||||
}
|
||||
`,
|
||||
})
|
||||
class TestCmp {
|
||||
f = form(signal(''), (p) => hidden(p, ({value}) => value() === ''));
|
||||
select = viewChild<ElementRef<HTMLSelectElement>>('select');
|
||||
options = ['one', 'two', 'three'];
|
||||
}
|
||||
|
||||
const fix = act(() => TestBed.createComponent(TestCmp));
|
||||
const cmp = fix.componentInstance as TestCmp;
|
||||
|
||||
expect(fix.componentInstance.select()).toBeUndefined();
|
||||
|
||||
act(() => cmp.f().value.set('two'));
|
||||
expect(fix.componentInstance.select()).not.toBeUndefined();
|
||||
expect(fix.componentInstance.select()!.nativeElement.value).toEqual('two');
|
||||
});
|
||||
|
||||
it('synchronizes with a custom value control', () => {
|
||||
@Component({
|
||||
selector: 'my-input',
|
||||
|
||||
Reference in New Issue
Block a user