5

I'm using a reactive form.when an input state is invalid i show an error.this is my view:

<div class="form-group">
    <label for="username">Username</label>
    <input name="username"
           type="text"
           class="form-control"
           id="username"
           formControlName="username"
           #username/>
    <div class="alert alert-danger"
         *ngIf="formDir.form.controls.username.touched && 
                formDir.form.controls.username.invalid">
        This field is required.
    </div>
</div>

<div class="form-group">
    <label for="password">Password</label>
    <input type="password"
           id="password"
           class="form-control"
           name="password" />
</div>

<pre>{{myForm.value | json}}</pre>
<button class="btn btn-primary" type="submit">Sign in</button>

every time i want to use ngIf to show a validation error i have to write this unwieldy code:

*ngIf="formDir.form.controls.username.touched && 
       formDir.form.controls.username.invalid">

it's more persecutor when you have more objects to validate.

by following documents on angular.io and this example i found a solution but i have to create an instance of every form control that i want to access it on view.

i'm looking for a solution like something we can use in template driven validation, using a temporary variable and ngModel like this:

<input type="text" class="form-control" name="username" #username="ngModel">
<div *ngIf="username.touched && username.invalid" class="alert alert- 
danger">Email is required</div> 

As i understand from this link there is no way to achieve this but this link is old and it may exists a solution in newer version of angular.

can you help me?

thanks

  • What about writing your own structural directive, that will take 1. control as an input parameter 2. error that should be check (by default required)? – Ashot Aleqsanyan Jun 03 '22 at 15:05

4 Answers4

1

Use an ngIf expression followed by a let, to rename the result of the expression:

<div *ngIf="formDir.form.get('username'); let c" class="form-group">
    <label for="username-id">Username</label>
    <input
       type="text"
       class="form-control"
       id="username-id"
       [formControl]="c" />
    <div class="alert alert-danger" *ngIf="c.touched && c.invalid">
        This field is required.
    </div>
</div>

You can also say:

<div *ngIf="formDir.form.controls.username; let c" ...>

If you don't happen to have a div or some other element you can use for the ngIf (the value of which is assumed to be always truthy), you can use an ng-container.

0

To show error based on validation for each field you can try :

<div *ngIf="formDir.form.controls[fieldName].invalid" class="alert alert- 
danger">Email is required</div> 

for this you do not need any other variable, in form-controls object we have validation. Please let me know if you need any more details

VISHNU
  • 948
  • 8
  • 15
  • I think Abolfazl Davoodi Shandiz was asking for a bit more elegant solution. I've run into similar problem and don't like using this long chain. – vlodko Jul 24 '18 at 17:51
0

I think you can use an error component:

  <div>         
    <input type="text" formControlName="foo">
    <control-error [control]="foo" [errorName]="'required'">
      Type your error message here
    </control-error>
  </div>

The error component template:

<div *ngIf="control.touched && control.errors?.[errorName]">
    <ng-content></ng-content>
</div>

Gain access to the form control instance that you pass to the error component with either a getter in the component class as shown in angular docs: get username() { return this.form.get('foo'); } or use form.get('foo') right within the template.

  • you can pass also the "error" like this [SO](https://stackoverflow.com/questions/57741343/angular-forms-how-to-avoid-multiple-ngif-divs-for-validation-error-messages/57744709#57744709) – Eliseo Jan 02 '22 at 09:02
  • Thanks to Eliseo for helping me improve my answer. – Adam Wilson Jan 03 '22 at 05:05
0

Attempting to use NgModel with a FormGroupDirective will result in the following error.

ERROR Error: ngModel cannot be used to register form controls with a parent formGroup directive.

The FormControlName directive doesn't export itself for template bindings. However, the FormControlDirective does as ngForm. The catch is that FormGroup.controls are of type AbstractControl which results in a type error conflict with strict template type checking. This can be correct with a method that takes the control name and type casts to FormControl.

Example on StackBlitz

// component.component.html
<form [formGroup]="form">
  <hello name="{{ name.value }}"></hello>
  <input #name="ngForm" [formControl]="control('name')" />
</form>
// component.component.ts
form = new FormGroup({ name: new FormControl(`Name`) });

control(name: string): FormControl { return this.form.controls[name] as FormControl; 

This can just as easily be done with template driven forms without duplicating any logic in the component class.

// component.component.html
<hello name="{{ name.value }}"></hello>
<input #name="ngModel" [ngModel]="Name" />
Trevor Karjanis
  • 1,485
  • 14
  • 25