I am struggling with my custom checkbox not reflecting changes of ngModel
. I've probably read all relevant issues on SO and still can't find a solution that works for me.
export class CheckboxInputComponent extends AbstractInputComponent implements ControlValueAccessor, Validator {
@Input() public inxs: string;
@Input() public grouped = true;
@Input() public checked: boolean;
@Input() public labeled = true;
@Input() public name: string;
@Input() public intermediate = false;
@ViewChild('cb') public cb: ElementRef;
@ContentChild('checkBoxLabel') labelTemplate;
constructor ( protected cdr: ChangeDetectorRef ) {
super(cdr);
}
public toggleCheck(): void {
if (!this.grouped) {
this.value = !this.value;
this.checked = !this.checked;
}
this.intermediate = false;
}
private checkIntermediate(c: FormControl): void {
if ( this.cb ) {
if ( !(c.dirty || c.touched) ) {
this.cb.nativeElement.intermediate = this.intermediate;
} else {
this.cb.nativeElement.intermediate = false;
}
}
}
protected customValidate( c: FormControl ): unknown | null {
this.checkIntermediate(c);
if ( c.dirty || c.touched ) {
const noValue = this.hasNoValue(c);
if ( this.required && noValue ) {
return { 'required': true };
}
}
return null;
}
protected normalize ( v: any ): any {
return v;
}
protected hasNoValue(c: FormControl ): boolean {
return c.value !== true;
}
}
The abstract class it extends is:
@Directive()
export abstract class AbstractInputComponent implements OnChanges {
/**
* inner value
*/
protected innerValue: unknown = null;
protected innerErrors: AbstractInputErrors;
/**
* field label
*/
@Input() public label: string;
/**
* required boolean
*/
@Input() public required = false;
/**
* read only
*/
@Input() public isReadOnly = false;
/**
* placeholder to show
*/
@Input() public placeholder: string;
@Input() public disabled = false;
/**
* control reference
*/
@ViewChild('fieldInput') public fieldInput: NgModel;
public isFocused = false;
// infrastructure
public registerOnChange(fn: any) { this.propagateChange = fn; }
public registerOnTouched(fn: any) { this.propagateTouch = fn; }
public propagateChange = (_: any) => { };
public propagateTouch = (_: any) => { };
constructor(
protected cdr: ChangeDetectorRef
) { }
public ngOnChanges(): void {
if ( this.isReadOnly ) {
this.propagateChange(this.value);
}
this.cdr.detectChanges();
}
public onFocus(): void {
this.isFocused = true;
}
public onBlur(): void {
this.isFocused = false;
this.propagateTouch(true);
}
public get value(): any {
return this.innerValue;
};
@Input() public set value(value: any) {
if ( value !== undefined ) {
this.writeValue(value);
this.propagateChange(this.innerValue);
this.propagateTouch(true);
}
}
public writeValue(value: any): void {
if (value !== this.innerValue) {
this.innerValue = this.normalize(value);
}
}
public setDisabledState(state: boolean): void {
this.disabled = state;
}
public get errors(): AbstractInputErrors {
return this.innerErrors;
}
public set errors( err: AbstractInputErrors ) {
if ( this.fieldInput ) {
if ( err ) {
this.innerErrors = err;
}
this.fieldInput.control.setErrors(err);
}
}
public validate(c: FormControl): unknown | null {
this.innerErrors = (this.isReadOnly) ? null : this.customValidate(c);
this.errors = this.innerErrors;
return this.errors;
}
protected abstract normalize(value)
protected abstract customValidate(control)
protected abstract hasNoValue(value)
}
And the template:
<div class="ultim-checkbox"
[class.readonly]="isReadOnly"
[class.checked]="value"
[class.intermediate]="intermediate"
(click)="toggleCheck()">
<input type="checkbox"
[required]="required"
[checked]="checked"
[(ngModel)]="value"
[attr.intermediate]="intermediate || null"
#fieldInput="ngModel"
#cb>
<span><i class="ico"
[ngClass]="{
'i-check-fat': !intermediate,
'i-minus-fat': intermediate
}"></i></span>
</div>
Now, in the parent component it goes like this:
<ultim-checkbox *ngIf="multiEditMode"
[(ngModel)]="data.meta.isSelected"
(change)="onSelect(data)"></ultim-checkbox>
It only updates the checkbox state if I hover over it. If instead I swap it for the standard input type="checkbox"
it works just fine without hovering. Can you spot a problem?
Aucun commentaire:
Enregistrer un commentaire