Bug
boolean is passed to *ngIf and supposed to switch on when it is true
md-error with *ngIf doesn't work at all. It only responds on predefined directives like required.
<md-input-container>
<input mdInput [(ngModel)]="sample" name="sample" (keyup)="validateInput()">
<md-error *ngIf="isError">{{errMsg}}</md-error>
</md-input-container>
Validate input on every keyup and set isError to true if the input is invalid.
angular 4.0.0, material 2.0.0-beta.3, macOS10.12.4, chrome
We use the error with ngIf
in our demo and it works fine. This is most likely an issue with your setup.
Closing since we cannot reproduce; feel free to open a new issue if you have a reproduction.
I am seeing this behaviour as well using the latest version of Material (2.0.0-beta.3).
Just to re-iterate, I can only get the md-error to show up using the predefined directives (e.g required, minlength, maxlength).
Could it have something to do with the fact that @thisisgit and I are using template-driven forms and the demo referenced by @crisbeto uses model-driven/reactive?
I'm also seeing this. Even hardcoding the *ngIf result to be true
the error message still doesn't appear.
<md-input-container>
<input mdInput [(ngModel)]="fromInput">
<md-error *ngIf="true">Error message</md-error>
</md-input-container>
Also using template-driven form here.
Can you put together a Plunkr that shows the issue @zlepper? You can use this as a template.
@crisbeto http://plnkr.co/edit/q4ERXhznMsvbqSiyddfA
Apparently i can't get neither normal validation or just hardcoding the error to true working now.
Both of the cases in the Plunkr don't work, because you don't have a ControlValueAccessor
(e.g. an ngModel
or formControl
). The errors are supposed to show up when there is a ControlValueAccessor
that is invalid and touched.
And how do we make the ControlValueAccessor
invalid when it's not one of the build in validations jamieathans mentioned above?
I have edited the plunkr so the input field for the email now becomes red because something is wrong, but the md-error is still nowhere to be found: http://plnkr.co/edit/DYNUmQTxiJxnO28E1Uqz?p=preview
There a couple of issues with your examples:
ngIf="true"
(you can remove this btw), doesn't have any validation set up. If you add a required
attribute it'll work.#emailInput
refers to the DOM element, not the instance of ngModel
. You can get it working by changing it to #emailInput="ngModel"
.Here's a forked Plunkr with the above-mentioned changes. Note that to enable Angular's built-in email validation, you have to add the email
attribute.
Alright, however that still doesn't allow for custom validation error messages in the template-driven model, which is what I wanted to demonstrate with the first example by hardcoding the error message to always be there. The value should come from a custom validation like in the OP.
Said custom validation might go to an external server and fetch a result which indicates if the value is valid (Checking if a username is available on signup for example).
Yes it does, the default validators go through the exact same pipeline as the custom ones. Can you post the custom validator that you're trying to use?
As an aside, you can see some usage examples in our demo app.
Alright, thanks to your help i managed to figure it out, and can also say that it is working as intended. In short what i have done:
Create a custom validator
import {AbstractControl, NG_VALIDATORS, Validator} from "@angular/forms";
import {Directive, forwardRef} from "@angular/core";
const END_WITH_API_REGEX = /.*\/api\/?$/;
@Directive({
selector: '[noApi][ngModel],[noApi][formControl]',
providers: [
{ provide: NG_VALIDATORS, useExisting: forwardRef(() => NoApiValidator), multi: true }
]
})
export class NoApiValidator implements Validator {
validate(c: AbstractControl): { [key: string]: any; } {
return END_WITH_API_REGEX.test(c.value) ? {validateApi: false} : null
}
}
Added it to my declarations:
@NgModule({
declarations: [
AppComponent,
[...],
NoApiValidator
],
imports: [
BrowserModule,
FormsModule,
HttpModule,
[...]
],
bootstrap: [AppComponent]
})
export class AppModule {
}
And used it for something:
<md-input-container>
<input mdInput placeholder="url" [(ngModel)]="url" type="url" required noApi #urlInput="ngModel">
<md-error *ngIf="urlInput.errors">Something was wrong</md-error>
</md-input-container>
I thank you for your time, especially since it was a user error.
+1 to see this working with optional relying on *ngIf
, since the purpose of the md-error
is quite trivial.
That would be useful for the server-side validation reflection.
I have problems making Reactive form with FormGroup display md-error
. md-hint
works with the same code.
Here's a code and a working plunker: http://plnkr.co/edit/CR06nY?p=preview.
All validations work except the custom one. My workaround for now is to just use 'md-hint` with red font.
Take a look at last two inputs. Password validation error doesn't appear.
<form fxFlex="80"
fxLayout="column"
id="updateProfileForm"
name="updateProfileForm"
[formGroup]="updateProfileForm"
(ngSubmit)="updateProfile( $event, updateProfileForm.value )"
novalidate>
<md-input-container fxFlex="0 0 auto">
<input mdInput type="text" formControlName="firstName" placeholder="First name" required>
<md-error>First name is required</md-error>
</md-input-container>
<md-input-container fxFlex="0 0 auto">
<input mdInput type="text" formControlName="lastName" placeholder="Last name" required>
<md-error>Last name is required</md-error>
</md-input-container>
<md-input-container fxFlex="0 0 auto">
<input mdInput type="email" formControlName="email" placeholder="Email" required>
<md-error *ngIf="updateProfileForm.get('email').hasError('required')">Email is required</md-error>
<md-error *ngIf="updateProfileForm.get('email').hasError('email')">Please enter a valid email address</md-error>
</md-input-container>
<md-input-container fxFlex="0 0 auto">
<input mdInput type="password" formControlName="oldPassword" placeholder="Old password">
</md-input-container>
<span formGroupName="passwords" fxLayout="column">
<md-input-container fxFlex="0 0 auto">
<input mdInput type="password" formControlName="password" placeholder="Password">
</md-input-container>
<md-input-container fxFlex="0 0 auto">
<input mdInput type="password" formControlName="confirmPassword" placeholder="Repeat password">
<!--TODO investigate why <md-error> doesn't work-->
<md-hint *ngIf="updateProfileForm.get('passwords').hasError('nomatch')">Passwords do not match</md-hint>
</md-input-container>
</span>
<button type="submit" [disabled]="( !updateProfileForm.valid || !updateProfileForm.dirty )" hidden></button>
</form>
this.updateProfileForm = this.formBuilder.group( {
firstName: [ '', Validators.required ],
lastName: [ '', Validators.required ],
email: [ '', Validators.compose( [ Validators.email, Validators.required ] ) ],
oldPassword: [],
passwords: this.formBuilder.group( {
password: [ '' ],
confirmPassword: [ '' ]
}, { validator: this.matchingPasswords } )
} );
}
private matchingPasswords( control: AbstractControl ) {
const password = control.get( 'password' );
const confirm = control.get( 'confirmPassword' );
if ( !password || !confirm ) {
return null;
}
return password.value === confirm.value ? null : { nomatch: true };
}
@dzena See https://github.com/angular/material2/issues/4232#issuecomment-303886675 for more information. The plunker in that comment shows the workaround we've been using that works pretty well (emulates md-error
in every way except for the animation).
@dzena ..I'm trying to implement the above form and was wondering if there is a solution to make the md-error work on confirm password?
@webUIdevelopment see this example from https://github.com/angular/material2/issues/4232#issuecomment-303886675
I think that this is quite good conversation to ask something...
I'm trying to test md-error element. But unfortunately it can't be found in any possible way:
<md-input-container style="width: 100%" dividerColor="accent">
<input
mdInput
placeholder="login"
style="width: 100%"
formControlName="username">
<md-error id="usernameerror" class="empty-class">{{authResult?.username}}</md-error>
</md-input-container>
and test contains:
it('should not log in', () => {
expect(component.login({username: 'someone', password: 'somepassword'})).toBeUndefined();
expect(component.authResult.token).toBeUndefined();
expect(component.authResult.username).toEqual(['error']);
fixture.detectChanges();
const de: DebugElement = fixture.debugElement.query(By.css('md-error'));
expect(de).not.toBeNull();
});
I was trying to use:
const de: DebugElement = fixture.debugElement.query(By.css('md-error'));
const de: DebugElement = fixture.debugElement.query(By.css('#usernameerror'));
const de: DebugElement = fixture.debugElement.query(By.css('.empty-class'));
but all the time de is empty.
How can I get the element?
@mgrom check out the input tests from the source - they should help guide you
https://github.com/angular/material2/blob/master/src/lib/input/input-container.spec.ts#L639-L654
Seeing the same behavior. Started a stackoverflow which eventually led me here after thinking the bug may be due to md-error with *ngIf
https://stackoverflow.com/questions/44975120/angular-validator-maxlength-show-message-on-keypress
Something to note, it works if I place the md-error outside of the md-input-container.
Will probably use a styled md-hint until this is addressed
I'm facing same issue like @anthonyartese whenever I put md-error outside of md-input-container Condition works fine but not within it when can we get this bug resolved for md-error?
Thanks
@divyameher are you also (like @anthonyartese) trying to get it to display the error when dirty
instead of touched
? If so, see this answer to his question on how to configure it
Seems like it's also possible to use https://angular.io/api/forms/AbstractControl#setErrors to reflect an error state from the server.
I wonder, will it be addressed in some way in the future? Or this is "wonfix" and ngIf for md-error
doesn't work by design?
@whitebyte AFAICT by reading through this thread, there are no bugs with using *ngIf
, just a misunderstanding of how md-error
works.
invalid
and touched
md-error
in ng-container
, but it is expected behavior and easy to workaround@willshowell thank you for the summary.
While I understand that this is intended behavior, this is counter-intuitive and leads to obscure errors. I hope devs will change their mind on this issue.
@ewaschen see https://github.com/angular/material2/issues/8513 and the linked Stack Overflow answers
@willshowell I tried that example with the following
customErrorStateMatcher: ErrorStateMatcher = {
isErrorState: (control: FormControl | null) => {
if (control) {
const hasInteraction = control.dirty;
return (hasInteraction && control.parent.hasError("passwordMatchValidator"));
}
return false;
}
};
With my Confirm Password I also have a required
, so I want the required
to show if it is empty and the mismatch to show when the passwords are different, but hidden when the passwords are the same. I can't seem to achieve this logic in the error matcher. What I have above works for the password matcher but ignores the required. If I remove control.parent.hasError("passwordMatchValidator")
then the required shows but not the mismatch, so I can get one of them but not both.
So I updated the return
to be
return (hasInteraction && (control.hasError("required") || control.parent.hasError("passwordMatchValidator")));
Is this the best way of doing this?
This issue has been automatically locked due to inactivity.
Please file a new issue if you are encountering a similar or related problem.
Read more about our automatic conversation locking policy.
_This action has been performed automatically by a bot._
Most helpful comment
I have problems making Reactive form with FormGroup display
md-error
.md-hint
works with the same code.Here's a code and a working plunker: http://plnkr.co/edit/CR06nY?p=preview.
All validations work except the custom one. My workaround for now is to just use 'md-hint` with red font.
Take a look at last two inputs. Password validation error doesn't appear.