$dirty vs $invalid: What is the difference? - angularjs

I am a novice in angular. I am confused by $dirty and $invalid, they almost sound the same.
What is the difference between $dirty and $invalid used in email ng-model? Below is the scenario. It's an example form W3Schools.
<form ng-app="myApp" ng-controller="validateCtrl" name="myForm" novalidate>
<p>
Username:<br>
<input type="text" name="user" ng-model="user" required>
<span style="color: red" ng-show="myForm.user.$dirty && myForm.user.$invalid">
<span ng-show="myForm.user.$error.required">Username is required.</span>
</span>
</p>
<p>
Email:<br>
<input type="email" name="emaill" ng-model="email" required>
<span style="color: red" ng-show="myForm.email.$dirty && myForm.email.$invalid">
<span ng-show="myForm.email.$error.required">Email is required.</span>
<span ng-show="myForm.email.$error.email">Invalid email address.</span>
</span>
</p>
<p>
<input type="submit" ng-click="Count()"
ng-disabled="myForm.$invalid" title="Submit" value="Submit">
</p>
</form>
EDIT 1:
I am wondering if I change the ng-model name from email to email8 it's not working anymore.
<input type="email" name="emaill" ng-model="email8" required>
Whether the validation is doing by myForm HTML element name which is not defined using ng attribute. How does it work?
ng-show="myForm.email.$dirty && myForm.email.$invalid"

$dirty: It will be TRUE, if the user has already interacted with the form.
$invalid: It will be TRUE, if at least one containing form and control is invalid.
Source
Also on Angular Docs
After the update in the Question...The validation is being done on the form element name. All the ng-models inside a form is tracked and that is how it is working.
Also changing a ng-model name will have no impact on validation. I tried your link and it works for me. That has to work.

$dirty means the user has changed the input value, $invalid means the address itself is invalid. Therefore the error is only shown if the user has actively changed the input value to either an empty or invalid value.

$dirty is True if user has already interacted with input. And $invalid is true if the the input is not a valid email address

$error is the object of errors where the key is the field validation name and value is the actual error message
<input type="email" name="emailName" ng-model="email" required>
for this example myForm.emailName.$error.email = true if email is not matched with format.
myForm.emailName.$error.required = true if you haven't added anyhting in input field
you can check valid or not of the field directly by using myForm.emailName.$valid but
the problem in your case is they want to show the user what is the error by having two cases. so they entered into $error object to check for the error is required email or invalid email
1.Email is required.
2.Invalid email address.
so they used $error object.
this is how myForm.emailName looks:
{"$viewValue":"ss","$validators":{},"$asyncValidators":{},"$parsers":[],"$formatters":[null],"$viewChangeListeners":[],"$untouched":false,"$touched":true,"$pristine":false,"$dirty":true,"$valid":false,"$invalid":true,"$error":{"email":true},"$name":"emailName","$options":null}
I think the example provide by you explains a lot.

You have done mistake That is why it was not working , can you see below code which you have written
<pre>
<input type="email" name="emaill" ng-model="email8" required>
<ng-show="myForm.email.$dirty && myForm.email.$invalid">
</pre>
Why it was not working because input name you have given "emaill" and in myForm.email.$dirty you have given "email" If both names should be same then it will work fine
<pre>
<input type="email" name="emaill" ng-model="email8" required>
<ng-show="myForm.emaill.$dirty && myForm.emaill.$invalid"></pre>

Related

Angular not validating form select

I'm new to angular so bear with me. I have a form with a dropdown, textbox and a button. The user has to select an option from the dropbox and enter a value in the textbox before the form becomes valid.
<form name='personDataSourceForm' novalidate ng-submit='personDataSourceForm.$valid && PersonCtrl.SaveDataItem()'>
<span>Invalid: {{personDataSourceForm.$invalid}}</span><br />
<span>valid: {{personDataSourceForm.$valid}}</span>
<div class="input-group">
<div class="input-group-addon">
<select class="form-control input-sm" required ng-model='PersonCtrl.sp.person.newItem.dataType' ng-options='opt as opt.text group by opt.dataType for opt in PersonCtrl.DataItemTypes'>
<option value="" disabled selected>Choose...</option>
</select>
</div>
<input type="text" class="form-control input-sm" ng-model='PersonCtrl.sp.person.newItem.value' required>
<div class="input-group-btn">
<button class="btn btn-default btn-sm" ng-class="{ 'btn-success' : PersonCtrl.sp.person.newItem.dataType.dataType && PersonCtrl.sp.person.newItem.value }" type="submit">Save</button>
<button class="btn btn-link btn-sm" type="button" ng-click="PersonCtrl.StopAddItem()">Cancel</button></div>
</div>
</form>
I quickly added 2 spans to show the validation state. When both are empty the form shows invalid which makes sense.
As soon as I type in a value in the textbox then suddenly the form is valid even though the dropdown still hasn't been changed.
Why is my dropdown not getting validated? I've even tried this solution AngularJS Dropdown required validation
My initial thought is that you already have that default value selected:
<option value="" selected>Choose...</option>
so it does technically have a value of "", which is fulfilling the required.
I think you will need to look at PersonCtrl.sp.person.newItem. The form becomes valid when both the dataType and value get solid. My guess is the item always has its dataType solid and valid so when the new value is entered the whole form becomes valid.
Why don't your select ad input have a name attribute? The name attribute is necessary for form validations to work properly.
I think form creates a map of name->validity for each input component and it could be that you have omitted it they both (select and input) map to the same validity object. If this is the case, then anyone becomes valid, effectively makes the status of the other one valid as well and hence they are both valid the form becomes valid.
Please add separate names for them and see if the problem is resolved. My opinion above is a strong guess and I have not dived into Angular code to check ng-form's behaviour.

ng-minlength and ng-pattern preventing binding

I have defined an input feild as
<form name="signUpForm">
<input type="text" name="username" ng-minlength="8" ng-maxlength="64" ng-model="user.username" ng-pattern="/((?=.*\d)(?=.*[a-z])(?=.*[A-Z])(?=.*[##$%^]))/">
</form>
And defined user in controller as
$scope.user{};
Now when I bind user.username value in HTML, its preventing it.
<p ng-if="user.username.length > 0">Display True</p>
Even if I simply bind its value in HTML as
{{user.username}}
Its not being displayed.
Now if I remove ng-pattern from input field as :-
<input type="text" ng-minlength="8" ng-maxlength="64" ng-model="user.username">
then only its binding and that too after satisfying ng-minlength="8" condition. Means '12345678' is displayed and '1234567' not.
One more issue is there i.e. if I use ng-pattern then ng-minlength validation is not working.
<p ng-if="signUpForm.username.$error.minlength">Please enter minimum length</p>
You can try setting the form.$setViewValue.length instead of the model's length
for example:
<p ng-if="signUpForm.username.$setViewValue.length > 0">Display True</p>
here's a solution i found:
How do I prevent AngularJS from unbinding a form input's value from its model when it's invalid?

Why name attribute required in AngullarJs validation

Friends, I am new to angularjs please explain why name attribute required for angularjs validation
<form name="lform" novalidate>
<input type="text" name="userName" ng-model="userName" required novalidate/>
<span style="color:red" ng-show="lform.userName.$dirty && lform.userName.$invalid">
<span ng-show="lform.userName.$error.required">Username is required.</span>
</span>
<br/>
</form>
If I remove name="userName" code not working, please explain this.
Update: If I remove "ng-model" it is not working, but I can change "ngmodel='newName'" is working, please explain this reason also.
This is just how HTML form works, name describe the parameter that will be sent to the server.
Angular's approach is to extend HTML and its behaviour, instead of inventing the wheel. Angular encapsulates "form" (see ngForm directive) and extend it. Because name is the unique id of an input in a form, it is also the unique id of the input in ngForm's collection.
ng-model is another directive that bind the value of the input into a variable in the current scope, it doesn't have to hold the same value as name.
Let's take your example and change ng-model:
<form name="lform" novalidate>
<input type="text" name="userName" ng-model="object.name" required novalidate/>
<span style="color:red" ng-show="lform.userName.$dirty && lform.userName.$invalid">
<span ng-show="lform.userName.$error.required">Username is required.</span>
</span>
<br/>
</form>
The validation will work, but the variable that will be updated in your scope is "object.name".
To sum it up, lform.userName holds the metadata and object.name will hold the actual data.
The answer is in your code.
<span ng-show="lform.userName.$error.required">Username is required.</span>
Angular is using the input name to store the error related information.
lform – your form name
username – your input name

angularjs ng-minlength validation is not working, form still being submitted

I am trying to submit the form on only successful validation.
validation is working for required but not working for ng-minlength
form input is invalid but form is still being submitted.
<form name="myForm" ng-submit="count = count + 1" ng-init="count=0" ng-app>
<div class="control-group" ng-class="{error: myForm.mobile.$invalid}">
<label class="control-label" for="mobile">Mobile</label>
<div class="controls">
<input type="text" name="mobile" placeholder="07XXXXXXXXX" ng-model="mobile" ng-minlength="11" required />
<span ng-show="myForm.mobile.$error.required" class="help-inline">Required</span>
<span ng-show="myForm.mobile.$error.minlength" class="help-inline">Mobile number should be minimum 11 character starting from 07</span>
</div>
</div>
<div class="control-group">
<div class="controls">
<input class="btn" type="submit" value ="submit" />
</div>
count: {{count}}<br />
<tt>myForm.$invalid = {{myForm.$invalid}}</tt><br/>
</div>
</form>
http://jsfiddle.net/pMMke/9/
what am I doing wrong.
I don't want to use submit button disable method.
This is what you are doing wrong: you are mixing two concepts, Angular validators and
HTML5 validators.
The required HTML5 validators, for instance, states that:
When present, it specifies that an input field must be filled out before submitting the form.
So, if you try to submit a form that has an input with this attribute, it will show a message explaining this to the user, and it will prevent the form from being sent. This is the behavior you want. Why isn't working for ng-minlength? Because ng-minlength is an Angular validator (you can tell because it begins with ng-), and it doesn't add any special behavior to the form. It simply set the input where it is located to invalid (and hence, the form), and let you decide what to do with it.
You have an option: you can use the pattern HTML5 validator, to specify the field requires at least 11 characters. It would like this:
<input type="text" pattern=".{11,}">
So when you submit a form containing this input, it will no be sent if the user has enter less than 11 characters.
But since we are it, and you are already using the pattern validator, you could use the regular expression in its full potential, and define something like:
<input type="text" pattern="07[0-9]{9}" />
Which will only admit values of 11 characters, that start by "07" and that contains only digits. I have modified your fiddle to show you how it would work: http://jsfiddle.net/helara/w35SQ/
I mistakenly used ngMaxlength="12" ngMinlength="6" instead of ng-minlength="6" ng-maxlength="12", it's working fine now.
Both ng-minlength & mg-maxlength works in AngularJS.
I've tested this in AngularJS version 1.3.
Make sure to use novalidate with <form> to disable browser's native validation.
This should work:
To enter mobile number
ng-show="myForm.mobile.$touched && myForm.mobile.$error.required"
For minimum length
ng-show="myForm.mobile.$touched && myForm.mobile.$error.minlength"
For maximum length
ng-show="myForm.mobile.$touched && myForm.mobile.$error.maxlength"
This work for me guys
<div class="mdl-textfield mdl-js-textfield mdl-textfield--floating-label">
<input ng-minlength="11" class="mdl-textfield__input" type="text" name="cpf" id="cpf" ng-model="avaliacao.cpf" ng-required="true" ng-pattern="/^\d+$/">
<label class="mdl-textfield__label" for="cpf">CPF *</label>
</div>
<p style="color: #d50000;" ng-show="myForm.cpf.$error.required && myForm.cpf.$dirty">Field Required</p>
<p style="color: #d50000;" ng-show="myForm.cpf.$error.pattern">Only numbers</p>
<p style="color: #d50000;" ng-show="myForm.cpf.$error.minlength">Min 11 Chars</p>
I'm facing the same issue, and I think you can only disable the button or ignore the entered value by yourself. You can also check the $valid property in your controller and ignore the value... It is not so nice, but I found no other way.

AngularJS form validation after action has been performed

What is the best practices for showing the validation errors only after the user clisks some button? The $.pristine and $.dirty are reflected immediately so doing something like this does not work...
<input name="email" id="email" type="email" required ng-model="user.email" placeholder="email">
<div ng-show="form.$dirty && form.email.$invalid">
<span class="error" ng-show="form.email.$error.required">Required!</span>
<span class="error" ng-show="form.email.$error.email">This is not a valid email.</span>
</div>
I suppose I could write some directive that could do this, but was just wondering if there was an easier way.
I'd make a custom variable called $scope.showErrors and when the user performs the action (like presses the button) then set $scope.showErrors to false. Then, your outer div would check for showErrors as an ng-show in addition to the other checks you're doing.

Resources