Skip to content
Closed
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Original file line number Diff line number Diff line change
Expand Up @@ -31,15 +31,15 @@ export const formControlBinding: any = {
/**
* @description
* * Syncs a standalone `FormControl` instance to a form control element.
*
*
* @see [Reactive Forms Guide](guide/reactive-forms)
* @see `FormControl`
* @see `AbstractControl`
*
* @usageNotes
*
* ### Registering a single form control
*
*
* The following examples shows how to register a standalone control and set its value.
*
* {@example forms/ts/simpleFormControl/simple_form_control_example.ts region='Component'}
Expand Down Expand Up @@ -185,8 +185,8 @@ export class FormControlDirective extends NgControl implements OnChanges {
ngOnChanges(changes: SimpleChanges): void {
if (this._isControlChanged(changes)) {
setUpControl(this.form, this);
if (this.control.disabled && this.valueAccessor !.setDisabledState) {
this.valueAccessor !.setDisabledState !(true);
if (this.valueAccessor !.setDisabledState) {
this.valueAccessor !.setDisabledState !(this.control.disabled);
}
this.form.updateValueAndValidity({emitEvent: false});
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -31,13 +31,13 @@ export const controlNameBinding: any = {
* @description
* Syncs a `FormControl` in an existing `FormGroup` to a form control
* element by name.
*
*
* @see [Reactive Forms Guide](guide/reactive-forms)
* @see `FormControl`
* @see `AbstractControl`
*
* @usageNotes
*
*
* ### Register `FormControl` within a group
*
* The following example shows how to register multiple form controls within a form group
Expand Down Expand Up @@ -283,8 +283,8 @@ export class FormControlName extends NgControl implements OnChanges, OnDestroy {
private _setUpControl() {
this._checkParentType();
(this as{control: FormControl}).control = this.formDirective.addControl(this);
if (this.control.disabled && this.valueAccessor !.setDisabledState) {
this.valueAccessor !.setDisabledState !(true);
if (this.valueAccessor !.setDisabledState) {
this.valueAccessor !.setDisabledState !(this.control.disabled);
}
this._added = true;
}
Expand Down
70 changes: 68 additions & 2 deletions packages/forms/test/value_accessor_integration_spec.ts
Original file line number Diff line number Diff line change
Expand Up @@ -64,7 +64,7 @@ import {dispatchEvent} from '@angular/platform-browser/testing/src/browser_util'
fixture.detectChanges();

const input = fixture.debugElement.query(By.css('input'));
form.valueChanges.subscribe({next: (value) => { throw 'Should not happen'; }});
form.valueChanges.subscribe({next: (value) => { throw new Error('Should not happen'); }});
input.nativeElement.value = 'updatedValue';

dispatchEvent(input.nativeElement, 'change');
Expand Down Expand Up @@ -481,7 +481,8 @@ import {dispatchEvent} from '@angular/platform-browser/testing/src/browser_util'
const assertOptionElementSelectedState = (selectedStates: boolean[]): void => {
const options = fixture.debugElement.queryAll(By.css('option'));
if (options.length !== selectedStates.length) {
throw 'the selected state values to assert does not match the number of options';
throw new Error(
Comment thread
jermowery marked this conversation as resolved.
Resolved
'the selected state values to assert does not match the number of options');
}
for (let i = 0; i < selectedStates.length; i++) {
expect(options[i].nativeElement.selected).toBe(selectedStates[i]);
Expand Down Expand Up @@ -1056,6 +1057,38 @@ import {dispatchEvent} from '@angular/platform-browser/testing/src/browser_util'
expect(fixture.componentInstance.control.status).toEqual('DISABLED');
});

describe('should support custom accessors with setDisabledState - formControlName', () => {
let fixture: ComponentFixture<CvaWithDisabledStateForm>;

beforeEach(() => { fixture = initTest(CvaWithDisabledStateForm, CvaWithDisabledState); });

it('sets the disabled state when the control is initally disabled', () => {
fixture.componentInstance.form = new FormGroup({
'login': new FormControl({value: 'aa', disabled: true}),
});
fixture.detectChanges();

expect(fixture.componentInstance.form.status).toEqual('DISABLED');
expect(fixture.componentInstance.form.get('login') !.status).toEqual('DISABLED');
expect(fixture.debugElement.query(By.directive(CvaWithDisabledState))
.nativeElement.textContent)
.toEqual('DISABLED');
});

it('sets the enabled state when the control is initally enabled', () => {
fixture.componentInstance.form = new FormGroup({
'login': new FormControl({value: 'aa', disabled: false}),
});
fixture.detectChanges();

expect(fixture.componentInstance.form.status).toEqual('VALID');
expect(fixture.componentInstance.form.get('login') !.status).toEqual('VALID');
expect(fixture.debugElement.query(By.directive(CvaWithDisabledState))
.nativeElement.textContent)
.toEqual('ENABLED');
});
});

it('should populate control in ngOnInit when injecting NgControl', () => {
const fixture = initTest(MyInputForm, MyInput);
fixture.componentInstance.form = new FormGroup({'login': new FormControl('aa')});
Expand Down Expand Up @@ -1363,6 +1396,27 @@ class WrappedValue implements ControlValueAccessor {
validate(c: AbstractControl) { return c.value === 'expected' ? null : {'err': true}; }
}

@Component({
selector: 'cva-with-disabled-state',
template: `{{disabled ? 'DISABLED' : 'ENABLED'}}`,
providers: [
{provide: NG_VALUE_ACCESSOR, multi: true, useExisting: CvaWithDisabledState},
]
})
class CvaWithDisabledState implements ControlValueAccessor {
// TODO(issue/24571): remove '!'.

disabled !: boolean;
onChange !: Function;

writeValue(value: any) {}

registerOnChange(fn: (value: any) => void) {}
registerOnTouched(fn: any) {}

setDisabledState(disabled: boolean) { this.disabled = disabled; }
}

@Component({selector: 'my-input', template: ''})
export class MyInput implements ControlValueAccessor {
@Output('input') onInput = new EventEmitter();
Expand Down Expand Up @@ -1409,6 +1463,18 @@ class WrappedValueForm {
form !: FormGroup;
}

@Component({
selector: 'wrapped-value-form',
template: `
<div [formGroup]="form">
<cva-with-disabled-state formControlName="login"></cva-with-disabled-state>
</div>`
})
class CvaWithDisabledStateForm {
// TODO(issue/24571): remove '!'.
form !: FormGroup;
}

@Component({
selector: 'ng-model-custom-comp',
template: `
Expand Down