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

1
  • 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)? Commented Jun 3, 2022 at 15:05

4 Answers 4

2

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.

Sign up to request clarification or add additional context in comments.

Comments

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

1 Comment

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.
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.

2 Comments

you can pass also the "error" like this SO
Thanks to Eliseo for helping me improve my answer.
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" />

Comments

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.