I am trying to create a wrapper object around an PrimeNG Calendar control and after years not developing with Angular I still have to note, that there is no easy way in extending a control and all it's control-functionality.
What I want is, that the necessary functionality (like setting the validation state, eg. "ng-pristine" or "ng-dirty") is passed to the inner control. But that doesn't work correctly. Maybe there is someone, who has solved this problem!
const noop = () => {
};
export const CUSTOM_INPUT_CONTROL_VALUE_ACCESSOR: any = {
provide: NG_VALUE_ACCESSOR,
useExisting: forwardRef(() => CalendarFieldComponent),
multi: true
};
@Component({
selector: 'calendar-field',
templateUrl: './calendar-field.component.html',
providers: [CUSTOM_INPUT_CONTROL_VALUE_ACCESSOR],
})
export class CalendarFieldComponent implements ControlValueAccessor, Validator {
@Input() required = false;
@ViewChild(NgModel) model?: NgModel;
private innerValue: any = '';
private onTouchedCallback: () => void = noop;
private onChangeCallback: (_: any) => void = noop;
private onValidatorChange: (_: any) => void = noop;
get value(): any {
return this.innerValue;
};
set value(v: any) {
console.log(this.model);
this.model?.control.markAsDirty();
if (v !== this.innerValue) {
this.innerValue = v;
this.onChangeCallback(v);
}
}
onBlur() {
this.onTouchedCallback();
}
writeValue(value: any) {
if (value !== this.innerValue) {
this.innerValue = value;
}
}
registerOnChange(fn: any) {
this.onChangeCallback = fn;
}
registerOnTouched(fn: any) {
this.onTouchedCallback = fn;
}
validate(control: AbstractControl): ValidationErrors | null {
return {'required': true};
}
registerOnValidatorChange(fn: () => void): void {
this.onValidatorChange = fn;
}
}
The template looks like the following:
<p-calendar [(ngModel)]="value" styleClass="inputfield w-full" appendTo="body" [required]="required" (blur)="onBlur()"></p-calendar>
When I have a FormGroup which contains the control above. When the Form is submitted, I want to validate all field, which already works by using the following code. All the empty fields have a red border (because of ng-invalid), except for the wrapped controls.
// code which validates all the fields when clicking on submit button
private validateForm(): boolean {
for (const controlKey of Object.keys(this.form.controls)) {
const control = this.form.controls[controlKey];
control.markAllAsTouched();
control.markAsDirty();
control.markAsTouched();
}
return !!this.form.valid;
}
The wrapper control gets the classes "ng-invalid ng-touched ng-dirty" whereas the inner control just get the classes "ng-untouched ng-pristine ng-invalid ng-star-inserted".
How can I synchronize this (from wrapper to inner)?