Siri0S Siri0S - 15 days ago 9
Javascript Question

Angular 2 - Custom Form Control - Disable

I have created a custom control using ControlValueAccessor that is composed of an

input[type=text]
and a datepicker.

When I use it in template-driven forms everything works fine.
But when I use the model-driven approach (reactive forms), the
disable()
method on the form control doesn't seem to have any effect whatsoever.

Is it possible to disable/enable my custom control programmatically as I do with every other form control in model-driven forms

EDIT

I should note that I'm using Angular v2.1.0 and that my methodology is pretty much the same as this as I have been using it as a guide.

EDIT

This is my custom control:

@Component({
selector: 'extended-datepicker',
templateUrl: './extended-datepicker.component.html',
styleUrls: ['./extended-datepicker.component.scss'],
providers: [
{
provide: NG_VALUE_ACCESSOR,
useExisting: forwardRef(() => ExtendedDatepickerComponent),
multi: true
}
]
})
export class ExtendedDatepickerComponent implements OnInit, ControlValueAccessor {
isDatepickerActive: boolean = false;
_selectedDate: Date;
selectedDateString: string = "";
@Input() disabled: boolean;
@Input() mask: any;
@Input() required: boolean;

@ViewChild('textInput') textInput: ElementRef;

get selectedDate(): Date {
return this._selectedDate;
}

set selectedDate(value: Date) {
this.selectedDateString = moment(value).format(STANDARD_DATE_FORMAT);
this._selectedDate = value;
}

propagateChange: Function;

@ViewChild(DatePickerComponent) datepicker: DatePickerComponent;

constructor() {
}

writeValue(value: Date) {
if (value) {
this.selectedDate = value;
this.selectedDateString = moment(value).format(STANDARD_DATE_FORMAT);
}
}

registerOnTouched(): void {
}

registerOnChange(fn: Function) {
this.propagateChange = fn;
}
// ...


This is the control's template:

<div class="calendar-wrapper row-small-margin"
(clickOutside)="isDatepickerActive = false;">

<div class="col-xs-10 col-small-padding">
<div class="input-group">

<span class="input-group-addon" role="button" (click)="prevDay()"
*ngIf="selectedDate">
<i class="fa fa-chevron-left"></i>
</span>

<input #textInput [textMask]="{mask: mask}"
[(ngModel)]="selectedDateString"
(ngModelChange)="inputChange()"
class="form-control" [required]="required"
[disabled]="disabled" (keyup)="onKeyPressed($event)">

<span class="input-group-addon" role="button" (click)="nextDay()"
*ngIf="selectedDate">
<i class="fa fa-chevron-right"></i>
</span>
</div>

<div *ngIf="isDatepickerActive" class="datepicker-wrapper">
<datepicker [(ngModel)]="selectedDate" (ngModelChange)="dateChange()"
[showWeeks]="false" [required]="required"
[formatDay]="dd" [formatMonth]="MM" [formatYear]="yyyy"
[disabled]="disabled">
</datepicker>
</div>
</div>

<div class="col-xs-2 col-small-padding">
<button class="btn btn-sm btn-datepicker" [disabled]="disabled"
(click)="toggleDatePicker()" type="button">
<img src="/assets/img/image.png">
</button>
</div>

</div>


And this is what I do in my form component:

this.myForm.controls['pickDate'].valueChanges.subscribe(val => {
if (!val) {
this.myForm.controls['date'].disable(); // This line here does nothing
}
});


How is it possible to respond to that
disable()
call inside my extended-datepicker and act accordingly?

Answer

Your component needs to implement the setDisabledState function which is defined in the ControlValueAccessor interface (see docs).

E.g. (assuming the renderer has been injected in the constructor):

setDisabledState(isDisabled: boolean) {
    this.renderer.setElementProperty(this.textInput.nativeElement, 'disabled', isDisabled);
    // disable other components here
}
Comments