Angular: Why does field $invalid is true in other view? - javascript

I have added some condition to show my revision field. Basically it will accept a number and a required field , so i added some validation check. I have excluded this field from 'edit' view. and for that i specified condition as well.
ng-show="editMode=='addNew' || editMode=='addDate'"
even though in edit view my field is not showing up.. but somewhere $invalid is becoming true for all view
<div class="form-group" ng-show="editMode=='addNew' || editMode=='addDate'">
<label for="editmyRevision" ng-class="{'col-sm-3':editMode=='addNew'}" class="col-md-2 control-label">Revision</label>
<div ng-class="{'col-sm-9':editMode=='addNew'}" class="col-md-10">
<input class="form-control" ng-model="editmyRevision"name="revision" ng-required="editMode=='addNew' || editMode =='addDate'" ng-maxlength="5" ng-Pattern="/^[0-9]*$/"></input>
<span class="has-error help-block" data-ng-show="prodEdit.revision.$invalid">Acceptable formats: 100~99999</span>
</div>
</div>
What am i doing wrong here?

ng-show will not remove the input from the form. It will just set display:none style to it, so it will still make the form invalid.
Try using ng-if instead.
<div class="form-group" ng-if="editMode=='addNew' || editMode=='addDate'">

Many error syntax in your code. $invalid apply for form not input.
Change:
<input class="form-control" ng-model="editmyRevision"name="revision" ng-required="editMode=='addNew' || editMode =='addDate'" ng-maxlength="5" ng-Pattern="/^[0-9]*$/"></input>
<span class="has-error help-block" data-ng-show="prodEdit.revision.$invalid">Acceptable formats: 100~99999</span>
To:
<input class="form-control" ng-model="editmyRevision" name="revision" ng-pattern="/^[0-9]{3,5}$/"/>
<span class="has-error help-block" data-ng-show="prodEdit.revision.$error">
Acceptable formats: 100~99999
</span>

Related

Remove error validation message when user clicks/moves out of the textbox

I am working on a reactive form in angular. Facing this problem where a field that is not required should have some validations when it is dirty or touched but as soon as the user is out of this textbox/field, the validation message should just go away. I have tried using ng-invalid but it is not working as the field when loaded for the first time is having ng-invalid class. The following is the code -
<div class="form-group">
<label>Street Name</label>
<input type="text" class="form-control" formControlName="streetName">
<span class="text-danger"
*ngIf="registerForm.get('streetName').touched || registerFormControl.get('streetName').dirty" class="Required">
<span *ngIf="registerForm.get('streetName').error?.pattern || registerForm.get('streetName').error?.minLength">
Pattern & Minlength error
</span>
<span class="text-danger"
*ngIf="registerForm.get('streetName').error?.monthError || registerForm.get('streetName').error?.otherError">
Month and Other Error
</span>
</span>
</div>
FormGroup Validation -
streetName:['',{
Validators: [
Validators.pattern(0-9),
Validators.minLength(9),
this.customValidations.streetValid
],
updateOn: 'blur'
}]
How do I get this validation dissappear?
You can use the focus and blur events to track if and when a user is in an input field or not.
<input (focus)="onFocus()" (blur)="onBlur()">
In this code example onFocus() is called when the user clicks/is-in the input box. onBlur() is called when the user clicks out of the input box.
We can use this to better distinguish if we should display the error message or not.
Let's say you have two inputs: Street Name and Street Address. We will create an onFocus() function that handles which item is focused and an onBlur() function that will clear the focused selection.
// Class variables
public selectedField = "";
function onFocus(identifier : string) {
selectedField = identifier; // set the field
}
function onBlur() {
selectedField = ""; // clear the field
}
Now, on our inputs:
<input (focus)="onFocus('streetName')" (blur)="onBlur()" type="text" class="form-control" formControlName="streetName">
<input (focus)="onFocus('streetAddress')" (blur)="onBlur()" type="text" class="form-control" formControlName="streetAddress">
Finally, we can handle if we should display the error message or not. All we need to do is add one more condition to the *ngIf of the error span.
<!--Example Street Name Error Span -->
<span class="text-danger" *ngIf="selectedField == 'streetName' && . . . ">
Invalid Street Name
</span
<!--Example Street Address Error Span -->
<span class="text-danger" *ngIf="selectedField == 'streetAddress' && . . . ">
Invalid Street Address
</span
If you'd like a better understanding on how focus works, you can find it here.

Angular validation messages don't work with ng-show and two inputs

I have implemented a form with a mode. Form can have 'Create' or 'Edit' mode. Depending on the mode it shows some div in one place of the layout or another. Div content is the same and it's input and some validation messages for it.
Here's simplified example.
View:
<div ng-app="myApp">
<div ng-controller="MyCtrl">
<form name="editForm">
<div ng-show='mode == "Edit"'>
<div class="form-group" ng-class="{true:'has-error',false:''}[editForm.FirstName.$valid === false && editForm.FirstName.$dirty]">
<input type="text" ng-model="foo" ng-maxlength="5" name="foo" required />
<div class="help-block" ng-messages="editForm.foo.$error" ng-if="editForm.foo.$dirty">
<p ng-message="required">Required</p>
<p ng-message="maxlength">Too long</p>
</div>
</div>
</div>
<div ng-show='mode == "Create"'>
<div class="form-group" ng-class="{true:'has-error',false:''}[edit.foo.$valid === false && edit.foo.$dirty]">
<input type="text" ng-model="foo" ng-maxlength="5" name="foo" required />
<div class="help-block" ng-messages="editForm.foo.$error" ng-if="editForm.foo.$dirty">
<p ng-message="required">Required</p>
<p ng-message="maxlength">Too long</p>
</div>
</div>
</div>
</form>
<div>
Mode: {{mode}} <br>
Value: {{foo}} <br>
Is form valid: {{editForm.foo.$valid}} <br>
</div>
</div>
</div>
Controller:
var myApp = angular.module('myApp',['ngMessages']);
myApp.controller('MyCtrl',function($scope){
$scope.mode = 'Edit';
});
Here's JSFiddle with working example.
The problem is - validation messages work properly only when the last input is shown. In Edit mode - even if it's the same - messages don't show correctly.
Instead of ng-show use ng-if directive.
ng-show causes browser to render both div elements, with ng-hide class on the element where ng-show expression is evaluated as false.
ng-if on the other hand causes div element to be not rendered if ng-if expression is false.

Angular setPristine on ngBlur

I have a form with password field for which I implemented a password directive.
I currently implemented only 1 validation but I've a list of validations on the field.
I want them to displayed in either red or green depending on valid/invalid respectively - when the user starts typing into the field. If the users control goes out of the box AND all validations are passed, I want to set the field to valid and set it to pristine so that the validation list won't show up.
However if any of the validations fail, I want all of them to be seen even if the field is out of focus. Below is my snippet for the form group.
<div class="form-group">
<label for="inputPass" class="col-sm-3 control-label text-sm text-left">Password</label>
<div class="col-sm-9">
<input type="password" placeholder="Password"
class="form-control" ng-model="registerAccount.password"
required name="inputPass" id="inputPass"
password ng-blur="form.inputPass.$invalid ? return: form.inputPass.$setPristine">
<div ng-show="form.inputPass.$dirty" class="help-block">
<p class="text-danger" ng-show="form.inputPass.$error.required">
Password is required.
</p>
<p ng-class="form.inputPass.$error.invalidLength ? 'text-danger' : 'text-success'">
Password should be atleast 8 characters.
</p>
</div>
</div>
</div>
Following is my directive
'use strict';
angular.module('nileLeApp')
.directive('password', function () {
return {
restrict: 'A',
require: 'ngModel',
link: function ($scope, $element, $attrs, ngModelCtrl) {
$scope.$watch($attrs.ngModel, function (value) {
if (value) {
var length = (value.length >= 8);
ngModelCtrl.$setValidity('invalidLength', length);
}
});
}
};
});
When the focus out of the field, the validation list is still showing up. I was expecting it to be hidden because the field is being set to pristine. Any ideas ? I wanted it to be similar to password field in https://dl.dropboxusercontent.com/u/636000/password_verification/index.html. As the user types the password, the validations are reflected in red/green.
You are not calling $setPristine method. Should be form.inputPass.$setPristine():
ng-blur="form.inputPass.$invalid ? return: form.inputPass.$setPristine()"
or cleaner variation:
ng-blur="form.inputPass.$valid && form.inputPass.$setPristine()"
You may not need to use a special directive:
<form name="testForm">
<input ng-model="testVal" name="testVal" required ng-minlength="3" ng-maxlength="10" ng-pattern="/^\w+$/">
<div ng-show="testForm.$invalid">
<div ng-class="{'errors':testForm.testVal.$error.required,'success':!testForm.testVal.$error.required}">Required</div>
<div ng-class="{'errors':testForm.testVal.$error.minlength,'success':!testForm.testVal.$error.minlength}">Minlength</div>
<div ng-class="{'errors':testForm.testVal.$error.maxlength,'success':!testForm.testVal.$error.maxlength}">Maxlength</div>
<div ng-class="{'errors':testForm.testVal.$error.pattern,'success':!testForm.testVal.$error.pattern}">Pattern</div>
</div>
</form>
This code does the same thing and given you the link: dl.dropboxusercontent.com/u/636000/password_verification/index.html
If you need to establish a more sophisticated checks, you can use the following directive use-form-error:
Live example on JsFiddle
<form name="testForm">
<input ng-model="testVal" name="testVal" required ng-minlength="3" ng-maxlength="10" ng-pattern="/^\w+$/" use-form-error="containWow" use-error-expression="testVal.indexOf('wow')>-1">
<div ng-show="testForm.$invalid">
<div ng-class="{'errors':testForm.testVal.$error.required,'success':!testForm.testVal.$error.required}">Required</div>
<div ng-class="{'errors':testForm.testVal.$error.minlength,'success':!testForm.testVal.$error.minlength}">Minlength</div>
<div ng-class="{'errors':testForm.testVal.$error.maxlength,'success':!testForm.testVal.$error.maxlength}">Maxlength</div>
<div ng-class="{'errors':testForm.testVal.$error.pattern,'success':!testForm.testVal.$error.pattern}">Pattern</div>
<div ng-class="{'errors':testForm.testVal.$error.containWow,'success':!testForm.testVal.$error.containWow}">It's 'wow' contains</div>
</div>
</form>

Do not trigger form.$invalid on first load

Having such form
<div ng-controller="FormController as f_ctrl">
<form ng-submit="f_ctrl.submit()" name="myForm">
<input type="text" ng-model="f_ctrl.user.username"
required
ng-minlength="4"/>
<input type="text" ng-model="f_ctrl.user.password"/>
<input type="submit" value="Submit" ng-disabled="myForm.$invalid">
</form>
</div>
and such controller
.controller('FormController', [function() {
var self = this;
self.submit = function() {
console.log('User submitted form with ' + self.user.username)
}
}]);
I have a problem: when page first loads it immediately shows red border on username field, even before I start typing anything.
I need to highlight invalid fields only after first submission. Can this be done using form.$invalid ?
You have to use $pristine for that. It is true when form controller is not changed. so when you change textbox data its comes false.
Small example for you.
<div class="form-group" ng-class="{ 'has-error' : userForm.password.$invalid && !userForm.password.$pristine }">
<input id="passAnime" type="password" name="password" ng-model="user.password" class="form-control input-md" placeholder="Password" tabindex="5" ng-maxlength="25" ng-minlength="6" required>
<span ng-show="userForm.password.$dirty && userForm.password.$invalid">
<p ng-show="userForm.password.$error.required" class="error-messages">
Your password is required.
</p>
<p ng-show="userForm.password.$error.minlength" class="error-messages">
Your password is too short. Minimum 6 chars.
</p>
<p ng-show="userForm.password.$error.maxlength" class="error-messages">
Your password is too long. Maximum 25 chars.
</p>
</span>
</div>
Angular has helpers that tell you if the form (or form field) is $dirty (user has typed something) or if the form is $touched (the blur event has been triggered on the input). See this demo.
I need to highlight invalid fields only after first submission.
Unfortunately, Angular doesn't support that. But you could implement it yourself rather easily:
Controller
function FormController() {
var vm = this;
vm.submitAttempted = false;
vm.submit = function(isValid) {
if (isValid) {
// do stuff
}
else {
vm.submitAttempted = true;
}
};
}
HTML
<div ng-app='app'>
<div ng-controller='FormController as vm'>
<form name='fooForm' ng-submit='vm.submit(fooForm.$valid)' novalidate>
<label>Username</label>
<input
name='username'
type='text'
ng-model='vm.user.username'
required
ng-minlength='4'
ng-class="{'invalid': vm.submitAttempted && fooForm.username.$invalid}">
<br /><br />
<button type='submit'>Submit</button>
</form>
</div>
</div>
CSS
.invalid {
border-color: red;
}
Demo
I have a problem: when page first loads it immediately shows red border on username field, even before I start typing anything.
That's probably because you have the following CSS class:
.ng-invalid {
border-color: red;
}
Angular will always apply the ng-invalid class to fields that are invalid, and there's nothing you could do about that. So if you don't always want invalid fields to have a red border, you can't use that class and you should do it in a way similar to what I proposed above.
Also, check out ngMessages.
You can disable the default styling on the input field that is adding the red border by default, by adding the following CSS:
input:required {
-moz-box-shadow: none;
box-shadow: none;
}
Then if you want to highlight the field when the form is submitted, you will need to ensure that the form and form fields have relevant name attributes. Doing this will allow you to check if the field is valid or not and apply a class to your text field when it is invalid:
<input type="text" name="username" ng-class="{ 'invalid-field' : f_ctrl.myForm.username.$invalid && !f_ctrl.myForm.username.$pristine }" required />
f_ctrl.myForm and f_ctrl.myform.username will have additional properties that you can use/check to determine if the form or fields are invalid or not, or if they have been modified at any point (e.g. f_ctrl.myform.username.$dirty). You should be able to view these properties on your page by adding the follow HTML:
<div>
<pre>{{f_ctrl.myForm | json}}</pre>
</div>
Or, you could output self.myForm to the console from your controller to view it's properties
console.log(self.myForm);

How to validate input field inside ng-repeat

I want to validate an input field where i want to be able to check whether the current input is greater than the previous input.
Here is what i mean
<div class="col-xs-10" ng-repeat="period in trim.rent_period" >
<div class="col-xs-6">
<div class="form-group">
<label class="col-xs-5 control-label" for="rentperiod">Rental Period
<span class="colon--label">:</span>
</label>
<div class="col-xs-6">
<input id="rentperiod" name="rentperiod" type="text" class="form-control" ng-model="rent.period" ng-change="checkRentPeriod($index);" required>
</div>
</div>
</div>
</div>
<div class="col-xs-2">
<i class="pull-left fa fa-plus-circle add-rent--icon" ng-click="addRent(currentIndex);"></i>
</div>
Here the add button adds an input into the list , and i want to make sure that the current input is greater than the previous input.
Try to wrap your code with form tag. And then check for validation of form if everything is okay. You can do this by following this guide here as a way to solve your question
https://docs.angularjs.org/guide/forms
change your ng-model="rent.period" to correct, something starting from "period", like ng-model="period.rent"
no need for extra method ng-change="checkRentPeriod($index);"
add that simple block after input:
<span ng-if="$index > 0 && period.rent && period.rent > trim.rent_period[$index - 1].rent">
Rent is greater than {{trim.rent_period[$index - 1]}}
</span>

Categories