I have an angular reactive form with default Validation.required and a CustomValidation.
Inside the CustomValidation I intended to check if the control is touched, but somehow this is not working.
import {
CustomValidation
} from './CustomValidator';
#Component({
selector: 'my-app',
templateUrl: './app.component.html',
styleUrls: ['./app.component.css'],
})
export class AppComponent implements OnInit {
customForm: FormGroup;
constructor(private fb: FormBuilder) {}
ngOnInit() {
this.customForm = this.fb.group({
customInput: [
'', [Validators.required, CustomValidation.customEmailValidation()],
],
});
}
}
// CustomValidation.ts
import {
AbstractControl,
ValidationErrors,
ValidatorFn
} from '#angular/forms';
export class CustomValidation {
static customEmailValidation(): ValidatorFn {
return (control: AbstractControl): ValidationErrors | null => {
if (control.touched && control.value.length === 0) {
console.log(control);
return {
customError: {
hasError: true,
errorType: 'empty field', // this can be any name
errorLabel: 'test',
},
};
}
return null;
};
}
}
<form [formGroup]="customForm">
<input formControlName="customInput" />
<button [disabled]="this.customForm.invalid">Submit</button>
</form>
I am expecting that the console.log inside the static method customEmailValidation will log the control object when the field will be touched. By touch I mean, I only click on the input.But that is not happening.
I also tried using updateOn
customInput: ['', {validators:[CustomValidation.customEmailValidation(),Validators.required],updateOn:"blur"}]
Please help me in understanding why it is not working.
Stackblitz Demo
At first, before you touch it, form.touched is false.
So thats the first value.
That value is being taken for the first time as form.touched
So you will get touched property as false.
If you intend to make it touched, just go with
this.form.markAsTouched() and then do the logic.
You are describing the focusin event, not the touched state.
From the Angular docs:
touched: boolean Read-Only True if the control is marked as touched.
A control is marked touched once the user has triggered a blur event
on it.
You are expecting this:
By touch I mean, I only click on the input.But that is not happening.
Also, the custom validator should be agnostic to the form input state. You can achieve what you want by binding to the focusin event and using that to flip the touched state. I don't understand why you would want to do this from a UX perspective, but hey.
Template
<form [formGroup]="customForm">
<input (focusin)="onFocusIn($event)" formControlName="customInput" />
<button [disabled]="this.customForm.invalid">Submit</button>
</form>
<span *ngIf="this.customForm.invalid && this.customForm.touched"
>VERY SERIOUS ERROR</span
>
Component
onFocusIn(event) {
this.customForm.markAsTouched();
console.log('focus');
}
Validator
static customEmailValidation(): ValidatorFn {
return (control: AbstractControl): ValidationErrors | null => {
if (control.value.length === 0) {
console.log(control);
return {
// ...control.errors,
customError: {
hasError: true,
errorType: 'empty field', // this can be any name
errorLabel: 'test',
},
};
}
return null;
};
}
Stackblitz here.
You can read more about custom form controls here from the Angular docs.
Related
I want to add a custom unique validator that will validate that all label fields values are unique.
(I) When I change the form values, the value of this.form changes after it is passed in CustomValidator.uniqueValidator(this.form). How to fix this?
(II) Is there any way of doing this without using any package?
Note: Forms have default values on load. Here is the screenshot.
this.form = this.fb.group({
fields: this.fb.array([])
});
private addFields(fieldControl?) {
return this.fb.group({
label: [
{value: fieldControl ? fieldControl.label : '', disabled: this.makeComponentReadOnly}, [
Validators.maxLength(30), CustomValidator.uniqueValidator(this.form)
]],
isRequired: [
{value: fieldControl ? fieldControl.isRequired : false, disabled: this.makeComponentReadOnly}],
type: [fieldControl ? fieldControl.type : 'text']
});
}
static uniqueValidator(form: any): ValidatorFn | null {
return (control: AbstractControl): ValidationErrors | null => {
console.log('control..: ', control);
const name = control.value;
if (form.value.fields.filter(v => v.label.toLowerCase() === control.value.toLowerCase()).length > 1) {
return {
notUnique: control.value
};
} else {
return null;
}
};
}
in real life, username or email properties are checked to be unique. This will be very long answer I hope you can follow along. I will show how to check uniqueness of username.
to check the database, you have to create a service to make a request. so this validator will be async validator and it will be written in class. this class will be communicate with the service via the dependency injection technique.
First thing you need to setup HttpClientModule. in app.module.ts
import { HttpClientModule } from '#angular/common/http';
#NgModule({
declarations: [AppComponent],
imports: [BrowserModule, YourOthersModule , HttpClientModule],
providers: [],
bootstrap: [AppComponent],
})
then create a service
ng g service Auth //named it Auth
in this auth.service.ts
import { Injectable } from '#angular/core';
import { HttpClient } from '#angular/common/http';
#Injectable({
providedIn: 'root',
})
export class AuthService {
constructor(private http: HttpClient) {}
userNameAvailable(username: string) {
// avoid type "any". check the response obj and put a clear type
return this.http.post<any>('https://api.angular.com/username', {
username:username,
});
}
}
now create a class ng g class UniqueUsername and in this class:
import { Injectable } from '#angular/core';
import { AsyncValidator, FormControl } from '#angular/forms';
import { map, catchError } from 'rxjs/operators';
import { of } from 'rxjs';
import { AuthService } from './auth.service';
// this class needs to use the dependency injection to reach the http client to make an api request
// we can only access to http client with dependecny injection system
// now we need to decorate this class with Injectable to access to AuthService
#Injectable({
providedIn: 'root',
})
export class UniqueUsername implements AsyncValidator {
constructor(private authService: AuthService) {}
//this will be used by the usernamae FormControl
//we use arrow function cause this function will be called by a
//different context, but we want it to have this class' context
//because this method needs to reach `this.authService`. in other context `this.authService` will be undefined.
// if this validator would be used by the FormGroup, you could use
"FormGroup" type.
//if you are not sure you can use type "control: AbstractControl"
//In this case you use it for a FormControl
validate = (control: FormControl) => {
const { value } = control;
return this.authService.userNameAvailable(value).pipe(
//errors skip the map(). if we return null, means we got 200 response code, our request will indicate that username is available
//catchError will catch the error
map(() => {
return null;
}),
catchError((err) => {
console.log(err);
//you have to console the error to see what the error object is. so u can
// set up your logic based on properties of the error object.
// i set as err.error.username as an example. your api server might return an error object with different properties.
if (err.error.username) {
//catchError has to return a new Observable and "of" is a shortcut
//if err.error.username exists, i will attach `{ nonUniqueUsername: true }` to the formControl's error object.
return of({ nonUniqueUsername: true });
}
return of({ noConnection: true });
})
);
};
}
So far we handled the service and async class validator, now we implement this on the form. I ll have only username field.
import { Component, OnInit } from '#angular/core';
import { FormGroup, FormControl, Validators } from '#angular/forms';
import { UniqueUsername } from '../validators/unique-username';
#Component({
selector: 'app-signup',
templateUrl: './signup.component.html',
styleUrls: ['./signup.component.css'],
})
export class SignupComponent implements OnInit {
authForm = new FormGroup(
{
// async validators are the third arg
username: new FormControl(
'',
[
Validators.required,
Validators.minLength(3),
Validators.maxLength(20),
Validators.pattern(/^[a-z0-9]+$/),
],
// async validators are gonna run after all sync validators
successfully completed running because async operations are
expensive.
this.uniqueUsername.validate
),
},
{ validators: [this.matchPassword.validate] }
);
constructor(
private uniqueUsername: UniqueUsername
) {}
//this is used inside the template file. you will see down below
showErrors() {
const { dirty, touched, errors } = this.control;
return dirty && touched && errors;
}
ngOnInit(): void {}
}
Final step is to show the error to the user: in the form component's template file:
<div class="field">
<input formControl="username" />
<!-- this is where you show the error to the client -->
<!-- showErrors() is a method inside the class -->
<div *ngIf="showErrors()" class="ui pointing red basic label">
<!-- authForm.get('username') you access to the "username" formControl -->
<p *ngIf="authForm.get('username').errors.required">Value is required</p>
<p *ngIf="authForm.get('username').errors.minlength">
Value must be longer
{{ authForm.get('username').errors.minlength.actualLength }} characters
</p>
<p *ngIf="authForm.get('username').errors.maxlength">
Value must be less than {{ authForm.get('username').errors.maxlength.requiredLength }}
</p>
<p *ngIf="authForm.get('username').errors.nonUniqueUsername">Username is taken</p>
<p *ngIf="authForm.get('username').errors.noConnection">Can't tell if username is taken</p>
</div>
</div>
You could create a validator directive that goes on the parent element (an ngModelGroup or the form itself):
import { Directive } from '#angular/core';
import { FormGroup, ValidationErrors, Validator, NG_VALIDATORS } from '#angular/forms';
#Directive({
selector: '[validate-uniqueness]',
providers: [{ provide: NG_VALIDATORS, useExisting: UniquenessValidator, multi: true }]
})
export class UniquenessValidator implements Validator {
validate(formGroup: FormGroup): ValidationErrors | null {
let firstControl = formGroup.controls['first']
let secondControl = formgroup.controls['second']
// If you need to reach outside current group use this syntax:
let thirdControl = (<FormGroup>formGroup.root).controls['third']
// Then validate whatever you want to validate
// To check if they are present and unique:
if ((firstControl && firstControl.value) &&
(secondControl && secondControl.value) &&
(thirdContreol && thirdControl.value) &&
(firstControl.value != secondControl.value) &&
(secondControl.value != thirdControl.value) &&
(thirdControl.value != firstControl.value)) {
return null;
}
return { validateUniqueness: false }
}
}
You can probably simplify that check, but I think you get the point.
I didn't test this code, but I recently did something similar with just 2 fields in this project if you want to take a look:
https://github.com/H3AR7B3A7/EarlyAngularProjects/blob/master/modelForms/src/app/advanced-form/validate-about-or-image.directive.ts
Needless to say, custom validators like this are fairly business specific and hard to make reusable in most cases. Change to the form might need change to the directive. There is other ways to do this, but this does work and it is a fairly simple option.
I mocked up a very small example of my problem here: https://github.com/lovefamilychildrenhappiness/AngularCustomComponentValidation
I have a custom component, which encapsulates an input field. The formControl associated with this input field has Validators.required (it is a required field). Inside the custom component, I have an onChange event which is fired when text is entered. I check if field is empty; if so, I add css class using ngClass. I also have set the registerOnChange of NG_VALUE_ACCESSOR, so I notify the form when the input changes. Finally, I implement NG_VALIDATORS interface to make the formControl invalid or valid.
My problem is I have a button that is clicked (it's not the submit button). When this button is clicked, I need to check if the custom component is blank or not, and if it is, change the css class and make the form invalid. I think the validate method of NG_VALIDATORS is doing that. But I need to change the css class of customComponent so background turns red. I spend severals hours on this and cannot figure it out:
// my-input.component.html
<textarea
[value]="value"
(input)="onChange($event.target.value)"
[ngClass]="{'failed-validation' : this.validationError }">
</textarea>
// my-input.component.ts
validate(control: FormControl): ValidationErrors | null {
if(!this.validationError){
return null
} else {
return { required: true };
}
}
private onChange(val) {
if(val.length > 0) {
this.value = val
this.validationError = false;
} else {
this.validationError = true;
}
// update the form
this.propagateChange(val);
}
// app.component.html
<form [formGroup]="reactiveForm">
<app-my-input formControlName="result"></app-my-input>
<input
value="Submit"
(click)="nextStep($event)"
type="button">
</form>
// app.component.ts
private nextStep(event){
// How do I dynamically change the class of the form control so I can change the style if formControl invalid when clicking the nextStep button
// pseudocode:
// if( !this.reactiveForm.controls['result'].valid ){
// this.reactiveForm.controls['result'].addClass('failed-validation');
// }
}
How can I get the css of the formControl to change in another component?
Since you using reactive form I have modified your custom form control. Here I have Use Injected NgControl Which is base class for all FormControl-based directives extend.
Try this:
import { Component, Input, forwardRef, OnInit } from "#angular/core";
import {
ControlValueAccessor,
NG_VALUE_ACCESSOR,
NgControl,
NG_VALIDATORS,
FormControl,
ValidationErrors,
Validator
} from "#angular/forms";
#Component({
selector: "app-my-input",
templateUrl: "./my-input.component.html",
styleUrls: ["./my-input.component.scss"]
})
export class MyInputComponent implements ControlValueAccessor, OnInit {
private propagateChange = (_: any) => {};
value = "";
onTouch: () => void;
constructor(public controlDir: NgControl) {
controlDir.valueAccessor = this;
}
writeValue(value) {
this.value = value;
}
registerOnChange(fn) {
this.propagateChange = fn;
}
registerOnTouched(fn) {
this.onTouch = fn;
}
onChange(value) {
this.propagateChange(value);
}
ngOnInit() {
const control = this.controlDir.control;
control.setValidators([control.validator ? control.validator : null]);
control.updateValueAndValidity();
}
}
Example
For More Information Forms Check this
In my application, I have a need for a reusable nested form component, such as Address. I want my AddressComponent to deal with its own FormGroup, so that I don't need to pass it from the outside.
At Angular conference (video, presentation) Kara Erikson, a member of Angular Core team recommended to implement ControlValueAccessor for the nested forms, making the nested form effectively just a FormControl.
I also figured out that I need to implement Validator, so that the validity of my nested form can be seen by the main form.
In the end, I created the SubForm class that the nested form needs to extend:
export abstract class SubForm implements ControlValueAccessor, Validator {
form: FormGroup;
public onTouched(): void {
}
public writeValue(value: any): void {
if (value) {
this.form.patchValue(value, {emitEvent: false});
this.onTouched();
}
}
public registerOnChange(fn: (x: any) => void): void {
this.form.valueChanges.subscribe(fn);
}
public registerOnTouched(fn: any): void {
this.onTouched = fn;
}
setDisabledState(isDisabled: boolean): void {
isDisabled ? this.form.disable()
: this.form.enable();
}
validate(c: AbstractControl): ValidationErrors | null {
return this.form.valid ? null : {subformerror: 'Problems in subform!'};
}
registerOnValidatorChange(fn: () => void): void {
this.form.statusChanges.subscribe(fn);
}
}
If you want your component to be used as a nested form, you need to do the following:
#Component({
selector: 'app-address',
templateUrl: './address.component.html',
styleUrls: ['./address.component.css'],
providers: [
{
provide: NG_VALUE_ACCESSOR,
useExisting: forwardRef(() => AddressComponent),
multi: true
},
{
provide: NG_VALIDATORS,
useExisting: forwardRef(() => AddressComponent),
multi: true
}
],
})
export class AddressComponent extends SubForm {
constructor(private fb: FormBuilder) {
super();
this.form = this.fb.group({
street: this.fb.control('', Validators.required),
city: this.fb.control('', Validators.required)
});
}
}
Everything works well unless I check the validity status of my subform from the template of my main form. In this case ExpressionChangedAfterItHasBeenCheckedError is produced, see ngIf statement (stackblitz code) :
<form action=""
[formGroup]="form"
class="main-form">
<h4>Upper form</h4>
<label>First name</label>
<input type="text"
formControlName="firstName">
<div *ngIf="form.controls['address'].valid">Hi</div>
<app-address formControlName="address"></app-address>
<p>Form:</p>
<pre>{{form.value|json}}</pre>
<p>Validity</p>
<pre>{{form.valid|json}}</pre>
</form>
Use ChangeDetectorRef
Checks this view and its children. Use in combination with detach to
implement local change detection checks.
This is a cautionary mechanism put in place to prevent inconsistencies
between model data and UI so that erroneous or old data are not shown
to a user on the page
Ref:https://blog.angularindepth.com/everything-you-need-to-know-about-the-expressionchangedafterithasbeencheckederror-error-e3fd9ce7dbb4
Ref:https://angular.io/api/core/ChangeDetectorRef
import { Component, OnInit,ChangeDetectorRef } from '#angular/core';
import { FormBuilder, FormGroup, Validators } from '#angular/forms';
#Component({
selector: 'app-upper',
templateUrl: './upper.component.html',
styleUrls: ['./upper.component.css']
})
export class UpperComponent implements OnInit {
form: FormGroup;
constructor(private fb: FormBuilder,private cdr:ChangeDetectorRef) {
this.form = this.fb.group({
firstName: this.fb.control('', Validators.required),
address: this.fb.control('')
});
}
ngOnInit() {
this.cdr.detectChanges();
}
}
Your Forked Example:https://stackblitz.com/edit/github-3q4znr
WriteValue will be triggered in the same digest cycle with the normal change detection lyfe cycle hook.
To fix that without using changeDetectionRef you can define your validity status field and change it reactively.
public firstNameValid = false;
this.form.controls.firstName.statusChanges.subscribe(
status => this.firstNameValid = status === 'VALID'
);
<div *ngIf="firstNameValid">Hi</div>
Try to use [hidden] in stand of *ngIf, it will work without ChangeDetectorRef.
Update URL : https://stackblitz.com/edit/github-3q4znr-ivtrmz?file=src/app/upper/upper.component.html
<div [hidden]="!form.controls['address'].valid">Hi</div>
I need to assign a custom validator to a FormGroup. I can do this at the time the FormGroup is created like this:
let myForm : FormGroup;
myForm = this.formBuilder.group({
myControl1: defaultValue,
myControl2: defaultValue
}, { validator: this.comparisonValidator })
comparisonValidator(g: FormGroup) {
if (g.get('myControl1').value > g.get('myControl2'.value)) {
g.controls['myControl1'].setErrors({ 'value2GreaterThanValue1': true });
return;
}
}
I have a situation though where I need to add the custom validator after I've instantiated the FormGroup, so I'm trying to do this after instantiating myForm, instead of adding the validator when the form is instantiated:
let myForm : FormGroup;
myForm = this.formBuilder.group({
myControl1: defaultValue,
myControl2: defaultValue
})
this.myForm.validator = this.comparisonValidator;
This gives me a compiler error:
Type '(g: FormGroup) => void' is not assignable to type 'ValidatorFn'.
Type 'void' is not assignable to type 'ValidationErrors'.
How do I assign a validator to my FormGroup so that the formGroup is passed as the argument to my comparisonValidator function?
Update - I've added a line showing where I'm doing a setErrors in my comparisonValidator, to make it clearer exactly how I'm trying to set a validation error.
I've created a stackblitz take a look.
In the component.ts file
import { Component } from '#angular/core';
import {FormBuilder,FormGroup, ValidationErrors, ValidatorFn} from '#angular/forms'
#Component({
selector: 'my-app',
templateUrl: './app.component.html',
styleUrls: [ './app.component.css' ]
})
export class AppComponent {
myForm: FormGroup;
defaultValue = 20;
constructor(private formBuilder: FormBuilder) {
this.myForm = this.formBuilder.group({
myControl1: this.defaultValue,
myControl2: this.defaultValue
});
debugger
this.myForm.setValidators(this.comparisonValidator())
}
public comparisonValidator() : ValidatorFn{
return (group: FormGroup): ValidationErrors => {
const control1 = group.controls['myControl1'];
const control2 = group.controls['myControl2'];
if (control1.value !== control2.value) {
control2.setErrors({notEquivalent: true});
} else {
control2.setErrors(null);
}
return;
};
}
}
In the component.html file
<div>
<form [formGroup]="myForm">
<input formControlName="myControl1" type="number">
<input formControlName="myControl2" type="number">
<br>Errors: {{myForm.get('myControl2').errors | json}}
</form>
</div>
For setting any validators (predefined or customs) after the instantiating the formGroup, you will need to use the setValiators() method of FormGroup.
For Ex:
let myFormGroup = this. _fb.group({
control1: new FormControl('1', [])
});
myFormGroup.setValidators(this.customValidators());
customValidators(): ValidatorFn {
let myFun = (cc: FormGroup): ValidationErrors => {
if(cc.valid) return null;
else return {something: 'someError'};
};
return myFun;
}
Thanks to #Anuradha Gunasekara - his answer is the most correct and complete solution. A 'quick fix' for my error was just to add a return type of any on the validator. I can still assign the custom validator to the FormGroup, and the FormGroup will be passed implicitly as the argument to my custom validator. This code will work:
let myForm : FormGroup;
myForm = this.formBuilder.group({
myControl1: defaultValue,
myControl2: defaultValue
})
this.myForm.validator = this.comparisonValidator;
comparisonValidator(g: FormGroup) : any {
if (g.get('myControl1').value > g.get('myControl2'.value)) {
g.controls['myControl1'].setErrors({ 'value2GreaterThanValue1': true });
}
}
Remove all form control white space form Form Group
custom validator :
export function formGroupRemoveWhitespaceValidator(form: FormGroup): ValidationErrors | null {
const keys: string[] = Object.keys(form.controls);
if (keys.length) {
keys.forEach(k => {
let control = form.controls[k];
if (control && control.value && !control.value.replace(/\s/g, '').length) {
control.setValue('');
}
});
}
return null;
}
component :
let myForm : FormGroup;
myForm = this.formBuilder.group({
myControl1: defaultValue,
myControl2: defaultValue
}, { validators: formGroupRemoveWhitespaceValidator });
These answers doesn't work for me, because I have other validators too. In my usecase, I have to set the errors also for the opposite field.
Perhaps it doesn't met the requirements of the OP exactly, but it hopefully helps others (like me), which landed on this site.
Here my is solution, which can be safely combined with other validators and also ensure, that the opposite field got an update.
// ...
this.form = this.formBuilder.group({
myControl1: this.formBuilder.control(defaultValue, [Validators.required, this.validateIsEqualTo('myControl2')]),
myControl2: this.formBuilder.control(defaultValue, this.validateIsEqualTo('myControl1')
});
this.form.get('myControl1').valueChanges
.pipe(
takeUntil(this.destroy$),
disinctUntilChanged())
.subscribe(() => this.form.get('myControl2').updateValueAndValidity());
this.form.get('myControl2').valueChanges
.pipe(
takeUntil(this.destroy$),
disinctUntilChanged())
.subscribe(() => this.form.get('myControl1').updateValueAndValidity());
// ...
public validateIsEqualTo(otherComponentId): ValidatorFn {
return (control: FormControl): ValidationErrors => {
const otherControl = this.form.get(otherComponentId);
return control.value !== otherControl.value ? {notEquivalent: true} : null;
}
}
I would like to create a directive that when it's given an variable with value of TRUE and if the user change the input value it won't write out that new value to the NgModel.
Example of use:
Directive selector: d-avoid-change
<input type="text" name="surname"
[(ngModel)]="model.surname"
[d-avoid-change]="true">
If the surname model that came from the server is "Foo" and the user change it to "Bar", the model.surname stays "Foo" and I can give a message to the user.
I was trying with another approach with the directive, that was to remove the input and click EventListener so the user would not be able to click, but that would seem like a bug.
I want to use it instead of the disabled property of HTML, because if I just use [disabled]="true" the user can open browser HTML inspector and change the value and save it, also I don't want to validate those permissions on the server. I've searched alot about this and couldn't find any suggestion, does anyone know how I could do that?
Found a way to build a directive that saves the original NgModel in a private variable and then if it receives the Input parameter as TRUE it will ignore the changing and put the original NgModel instead.
Also it overrides the native disabled so I don't need to use the directive and also the native disabled.
Directive code:
import {
Directive,
ElementRef,
AfterViewInit,
Input,
AfterContentInit,
ViewContainerRef,
Renderer2
} from '#angular/core';
import { NgModel } from '#angular/forms';
import { Observable } from 'rxjs/Observable';
declare let $;
#Directive({
selector: '[d-disabled]',
providers: [NgModel]
})
export class DisabledDirective implements AfterViewInit {
#Input('d-disabled')
set disabled(disabled: boolean) {
if (disabled) {
this.renderer.setAttribute(this.el.nativeElement, 'disabled', 'true');
} else {
this.renderer.removeAttribute(this.el.nativeElement, 'disabled');
}
this._disabled = disabled;
}
_disabled: boolean;
originalModel: any;
constructor(private el: ElementRef,
private ngModel: NgModel,
private renderer: Renderer2) {
this.ngModel.valueAccessor.registerOnChange = this.registerOnChange;
this.ngModel.valueAccessor.registerOnTouched = this.registerOnTouched;
this.originalModel = this.ngModel;
}
ngAfterViewInit() {
Observable.fromEvent(this.el.nativeElement, 'input')
.map((n: any) => n.target.value)
.subscribe(n => {
if (this._disabled) {
this.ngModel.viewToModelUpdate(this.originalModel.value);
this.ngModel.control.patchValue(this.originalModel.value);
this.ngModel.control.updateValueAndValidity({ emitEvent: true });
} else {
this.onChangeCallback(n);
}
});
}
private onChangeCallback: (_: any) => void = (_) => { };
private onTouchedCallback: () => void = () => { };
registerOnChange = (fn: (_: any) => void): void => { this.onChangeCallback = fn; };
registerOnTouched = (fn: () => void): void => { this.onTouchedCallback = fn; };
}
How to use it:
<input type="text" name="surname"
[(ngModel)]="model.surname"
[d-disabled]="true">
If anyone can help me to improve in any way this method, but this is working as I wanted.