Why does angular keep showing false when input is touched? - angularjs

I am new to angular. I have set up the following code to see if an input field has been touched. However when i type on the input field. It doesn't change. Just keeps showing false.
Not sure what I am doing wrong here. Any help would be really appreciated it.
<div ng-app='myApp' ng-form name="myForm">
<input type='text' name='address' ng-model="address" id='address'>
<h1> {{myForm.address.$touched}}</h1>
</div>
<script>
var app = angular.module("myApp",[]);
</script>

$touched in AngularJS jargon doesn't mean "was the value changed". That's $dirty's role.
$touched in AngularJS means that the field was blurred (that is, the field isn't selected anymore).
See it in action at plnkr.co.

Related

Angular js ng messages show error on init

In my project I have angularjs 1.5.10 and ng-messages 1.5.10. I use it in simple form:
<form class="form-horizontal" ng-submit="createBooking()" role="form" name="createBookingForm" novalidate>
<div class="form-group">
<label for="payment_details_last_name" class="col-sm-3 control-label">Last name</label>
<div class="col-sm-6">
<input type="text"
id="payment_details_last_name"
name="payment_details_last_name"
class="form-control"
ng-model="payment_details.last_name"
ng-required="true"
ng-maxlength="30" />
<div ng-messages="createBookingForm.payment_details_last_name.$error" role="alert">
<div ng-message="required">This field is required</div>
<div ng-message="maxlength">Your field is too long</div>
</div>
</div>
<div class="col-sm-3"></div>
</div>
</form>
In controller:
$scope.members = [{
'first_name': '',
'last_name': '',
'email': '',
'phone_number': '',
'date_of_birth': '',
}];
And on initial I always see error This field is required. I tried to create empty object in controller:
$scope.createBookingForm = {};
I also show form after initialized <div ng-if="initialized">
Nothing is working. Project using angular-seed skeleton
I saw dirty hacks like if $touched else, but I want to understand what is wrong...
Nothing is wrong about it, check out the sample in the official guide. They have required error shown by default. It seems wrong for the first glance, but this is the only correct way to handle such a case.
So basically, ng-messages does exactly what docs says:
ngMessages is a directive that is designed to show and hide messages
based on the state of a key/value object that it listens on.
the directive works in a real time and shows errors for current input state, that makes sense.
So if you want no messages to be shown by default, you should use some of approaches, discussed hundred of times
How to make ngMessage for required fields only show when dirty or submitting a form?
Angular : ng-message validation on submit click
AngularJS: Hiding ng-message until hitting the form-submit button
AngularJS 1.5.6 reset form & ng-messages
If you need some other improved behavior - there is no quick solution at the moment, you have to come up with your own validation engine that fit your needs.

Deletion Error with Email Validation in Angular

So I've recently taken over an Angular Giving Form Application. I am running validation on the email field using ng-pattern and displaying the errors on blur with ngMessages. The validation works great, however once the validation passes as $valid if the user decides they need to make a change in their email and begin to delete part of the first deletion deletes the last character of the email as expected, but the second deletion deletes the entire field forcing the user to start from scratch.
The regex for ng-pattern is being set in the controller scope with the variable $scope.emailre
The files are much to large to place here but here is the link to the site I am working on for my client.
https://epiqa.moodyglobal.org/corporate/
Snippet of Angular controller:
myApp.controller('mainCtrl', function($scope, localStorageService, $http) {
$scope.emailre = /^(([^<>()\[\]\\.,;:\s#"]+(\.[^<>()\[\]\\.,;:\s#"]+)*)|(".+"))#((\[[0-9]{1,3}\.[0-9]{1,3}\.[0-9]{1,3}\.[0-9]{1,3}])|(([a-zA-Z\-0-9]+\.)+[a-zA-Z]{2,}))$/;
Snippet of HTML Form:
<div class="row form-group">
<div class="col-sm-6">
<div>
<label class="label" for="txt_donorEmail">E-mail:</label>
<input ng-class="{ 'submitted-error' : givingForm.email.$invalid && submitted }" ng-model="email" type="text" id="email" name="email" class="textbox required full form-control" maxlength="50" ng-pattern="emailre" required />
</div>
<div ng-messages="givingForm.email.$error" ng-if="givingForm.email.$touched || submitted">
<div class="errorText" ng-message="required">This field is required</div>
<div class="errorText" ng-message="pattern">Enter a valid email</div>
</div>
</div>
</div>
I have tried changing the input type from type="text" to type="email" but when doing that any time the user types two (.) periods the field gets immediately deleted.
Please help any ideas are very welcome.
The behavior is caused by this section
$scope.$watch('email', function(value){
localStorageService.set('email',value);
$scope.emailValue = localStorageService.get('email');
});
By Angular documentation
The default behaviour in ngModel is that the model value is set to undefined when the validation determines that the value is invalid. By setting the allowInvalid property to true, the model will still be updated even if the value is invalid.
I'm not sure whether you want to save the invalid email into localStorage, though. Maybe you can add a check only update when the value is valid.

Detecting value change in ng-model without using $watch and form for application having large number of models

My application has a lot of models in the page. I want to detect whether user has changed value of any model on click of save. Using $watch on every model puts too much load, so don't want to use this method. Is there any good approach for this?
Small snippet is like below:
<div>
<div class="ttere2">
<input type="radio" name="nc2-radio3" ng-model="nc2PenaltyAfter" value="specificDays" />
<input class="ggfe1" ng-model="nc2AfterDays" ng-disabled="nc2PenaltyAfter!='specificDays'" type="number" min="1" max="100" step="1" value="1" />days</div>
<div class="admin_wp-line">
<input type="radio" name="nc2-radio3" ng-model="nc2PenaltyAfter" value="immediately"/> Immediately </div>
<div class="acfv1">model 1</div>
</div>
<div style="margin-top: 20px;"><button ng-click="saveData();">Done</button></div>
............too many inputs go here
</div>
Use .$dirty! Angular will set this on every element that is bound using ng-model, automatically, when it has been changed. It will also set it on the entire form. You can access it in code like this:
if ($scope.myForm.$dirty) {
// Your code here
}
Angular will provide six useful variables on the form, and every ngModel-bound element in your form: $dirty and $pristine, $valid and $invalid, and $touched and $untouched. You can mix and match these to drive a lot of useful behaviors, and they're available both in your controller (using the expression shown above) and your template (directly).

AngularJS Form is not in HTML

I am trying to use AngularJS Validation in order to validate a simple form, however I was having troubles getting my ng-class to show the correct class based off whether or not the input was dirty or not. Then when I looked at the actual HTML of the page, the <form> tags are not even in the document at all!
<form novalidate name="infoForm">
<p>To start, provide some basic information about the project.</p>
<ul class="ulFormGeneral">
<li>
<label>Company name</label>
<input id="CompanyName" ng-class="{ cvError : infoForm.CompanyName.$dirty }" ng-model="form.CompanyName" name="CompanyName" maxlength="100" type="text" required />
</li>
</ul>
</form>
I want the cvError class to be added to this input if it is dirty, but nothing happens when I look at this in the browser. What am I doing wrong that is causing the <form> to just leave the DOM and then not work with my Angular expressions?
Welcome to the Angular world, no forms required! Here, the model is king. It looks like the problem is the ng-model and ng-class are point at different places.
Point everything at form.CompanyName (assuming that is the model name is form in the $scope):
<input id="CompanyName" ng-class="{ cvError : form.CompanyName.$dirty }" ng-model="form.CompanyName" name="CompanyName" maxlength="100" type="text" required />
The ng-model binds to the $scope. When you change the input field, it is automatically updated in the $scope. No form is needed or hitting a submit button to get the data. The $scope is updated with each key stroke.
The controller should do the work of figuring out what to do with the changes in the model. For example, you can add an ng-click to a button that fires a function defined by the controller to save the model.

Validating repeating inputs inside an AngularJS form

I know this has been asked before, and have even found a well-upvoted answer here:
How to validate inputs dynamically created using ng-repeat, ng-show (angular)
But I can't get that solution to work. I've got an example here - annoyingly both jsFiddle and Plunkr seem to be down right now.
Here's the JS:
app.controller('DetailsCtrl', ['$scope', function($scope) {
$scope.loading = false;
$scope.formData = {
lines: [{
text: 'test.com'}]
};
$scope.addRow = function() {
$scope.formData.lines.push({text:null});
};
}]);
Here's the markup:
<body ng-controller="DetailsCtrl">
<div>
<form name="mainForm" novalidate class="form-vertical">
...some non-repeating inputs go in here...
<div data-ng-repeat="line in formData.lines" data-ng-form="lineForm">
<input type="text" name="myinput" data-ng-model="line.text" data-ng-required="true">
<span data-ng-show="mainForm.lineForm.myinput.$error.required">Error!</span>
</div>
New Line
</form>
</div>
</body>
You'll notice initially there is one text input with text in - great. Click the 'New Line' link. Because the new text input fails validation - BOTH text inputs get the warning span shown... I just want the one span relating to the one empty text input to show up.
As AngularJS relays on input names to expose validation errors, and you used the same name for all inputs, you faced with this effect.
So you can't generate input name dynamically, but instead you can use ng-form (see https://docs.angularjs.org/api/ng/directive/ngForm).
<form name="mainForm" novalidate class="form-vertical">...some non-repeating inputs go in here...
<div data-ng-repeat="line in formData.lines" data-ng-form="lineForm">
<input type="text" name="myinput" data-ng-model="line.text" data-ng-required="true">
<span data-ng-show="lineForm.myinput.$error.required">Error!</span>
</div> New Line
</form>
EDIT. Please note, access to error myinput.$error.required instead of lineForm.myinput.$error.required.
Please, checkout working fiddle http://jsfiddle.net/Y9g4q/7/.

Resources