How to validate form in AngularJs while using ng-repeat - javascript

I have form in angularjs, i was validate an email field.
The validation works great, but when i add another email field the validation works on all the items. But I only want the first field to be validate as required.
<form novalidate name="myForm">
<button class="btn btn-info btn-sm" ng-click="addNewChoice('email')">
<i class="fa fa-at"></i> Add Email
</button>
<br>
<div class="form-group row">
<div data-ng-repeat="email in emails">
<div class="col-md-4 col-sm-12" ng-class="{
'has-error' :isInputInvalid(myForm.email1),
'has-success' : isInputValid(myForm.email1)
}">
<label for="email{{ $index + 1}}">Email {{ $index + 1}}</label>
<input type="email" class="form-control" name="email{{ $index + 1}}" ng-model="formModel.emails[$index + 1]" id="email{{ $index + 1}}" placeholder="Enter email" required>
<span class="help-block" ng-show="myForm.email1.$error.required && myForm.email1.$dirty">Required</span>
<span class="help-block" ng-show="myForm.email1.$error.email">Email not valid!</span>
</div>
</div>
</div>
</form>
jsFiddle

In order to do something for only first item in a list rendered by ng-repeat, you can simply make use of $first.
So, instead of having just required, we can utilize ng-required like this:
ng-required="{{$first}}"
And, using $first at all the things used, we can get rid of validation for emails other than first!
Updated fiddle
EDIT: What I understood from the question is that you don't need validations for emails other than first. If your concern was that it says invalid for second even when first is invalid, check this fiddle which has individual validation for all emails entered.

Remove "&& myForm.email1.$dirty" in "Required span"

You can remove first element out of ng-repeat loop as it is required field and add then new choice email.

You can use ng-if="$first"
Try this
var myApp = angular.module('appMy', []);
myApp.controller('myCtrl', function($scope) {
console.log("hguy");
$scope.formModel = {};
$scope.emails = [{
id: 'email1'
}];
$scope.isInputValid = function(input) {
return input.$dirty && input.$valid;
}
$scope.isInputInvalid = function(input) {
return input.$dirty && input.$invalid;
}
$scope.addNewChoice = function(val) {
var newItemNo2 = $scope.emails.length+1;
$scope.emails.push({'id':'email'+newItemNo2});
};
});
.help-block {
color: #b34848;
}
.has-error label {
color: #a94442;
}
<script src="https://ajax.googleapis.com/ajax/libs/angularjs/1.4.8/angular.min.js"></script>
<div class="container" ng-app="appMy">
<div ng-controller="myCtrl">
<form novalidate name="myForm">
<button class="btn btn-info btn-sm" ng-click="addNewChoice()">
<i class="fa fa-at"></i> Add Email
</button>
<br>
<div class="form-group row">
<div data-ng-repeat="email in emails">
<div class="col-md-4 col-sm-12" ng-class="{
'has-error' :isInputInvalid(myForm.email1),
'has-success' : isInputValid(myForm.email1)
}">
<label for="email{{ $index + 1}}">Email {{ $index + 1}}</label>
<input type="email" class="form-control" name="email{{ $index + 1}}" ng-model="formModel.emails[$index + 1]" id="email{{ $index + 1}}" placeholder="Enter email" required>
<span ng-if="$first" class="help-block" ng-show="myForm.email1.$touched && myForm.email1.$invalid">Required</span>
<span class="help-block" ng-show="myForm.email{{ $index + 1}}.$error.email">Email not valid!</span>
</div>
</div>
</div>
</form>
</div>
</div>

Related

Apply autofocus on input inside ng-repeat

I want to autofocus the first input inside ngRepeat when my page loads and when I add a new item to array the focus should go for the last item of the ngRepeat and so on, doesn't matter how many items I add.
Here's my code actually:
<div class="add-top" ng-show="showstep=='step2'" style="position:relative;width:100%;">
<form name="EmailForm" novalidate accessible-form autocomplete="off" ng-submit="checkDup() && EmailForm.$valid ? Add() :''">
<div class="white text-center ">
<!-- && (emailDel | filter:'':true).length == emailDel.length -->
<div class=" bg-color-upload03 ticket-top">
<div class="col-md-12 " ng-init="emailDel=[1]">
<div class="newevent-nav01">
Enter email ids</div>
<div class="col-md-6 col-md-offset-3" ng-repeat="e in emailDel track by $index">
<input type="email" class="text-left" placeholder="Email ID" validate-email ng-model="emailDel[$index]" ng-init="emailDel[$index]=''" ng-required="emailDel.length==1" name="email_{{$index}}" id="email_{{$index}}">
<div class="col-md-2 col-md-offset-10 text-left" style="margin-top: -10px;" ng-show="(emailDel.length-1)==$index">
<img src="../../../path to + symbol-active icon" width="40%" ng-hide="(EmailForm.$valid && emailDel[ds.emailDel.length-1] !='')" />
<img src="../../..path to +symbol gray icon" width="40%" class="cursor-poi" ng-click="(EmailForm.$valid && emailDel[emailDel.length-1] !='') ? emailDel.push(emailDel.length+1) :''" ng-show="(EmailForm.$valid && emailDel[emailDel.length-1] !='')" />
</div>
<div class="col-md-12">
<span class="error" ng-show="EmailForm['email_'+$index].$touched && !EmailForm['email_'+$index].hasFocus">
<span ng-show="EmailForm['email_'+$index].$error.required">
Required
</span>
<span ng-show="EmailForm['email_'+$index].$error.email">
Invalid Email
</span>
<span ng-show="emailDel[$index]!='' && (emailDel | filter:emailDel[$index]:true).length>1">
Duplicate Email
</span>
</span>
</div>
</div>
</div>
<div class="col-md-4 col-md-offset-4">
<div class="col-md-10 col-md-offset-1">
<button type="submit" class="btn" ng-disabled="EmailForm.$invalid || (emailDel.length>1 && (emailDel | filter:'':true).length==emailDel.length)">Continue</button>
</div>
</div>
</div>
</div>
</form>
</div>
You can create your own directive for this.
When it loads you set focus to the $first element of your ngRepeat, when you starts to add elements, the focus should go to the $last.
Here's a snippet working:
angular.module('app', [])
.controller('mainCtrl', function($scope) {
$scope.email = ['test1#gmail.com', 'test2#hotmail.com', 'test3#stackoverflow.com'];
$scope.init = true;
$scope.add = function() {
$scope.email.push('');
$scope.init = false;
}
})
.directive('setFocus', function() {
return {
scope: {
setFocus: '='
},
link: function(scope, element) {
if (scope.setFocus) element[0].focus();
}
};
});
<!DOCTYPE html>
<html ng-app="app">
<head>
<script src="https://cdnjs.cloudflare.com/ajax/libs/angular.js/1.5.7/angular.min.js"></script>
</head>
<body ng-controller="mainCtrl">
<form name="delEmailForm" novalidate accessible-form autocomplete="off" ng-submit="testing() && delEmailForm.$valid ? Add() :''">
<div class="col-md-6 col-md-offset-3 text-center" ng-repeat="e in email track by $index">
<input type="email" set-focus="init ? $first : $last" class="inputbox-text-left" placeholder="Email ID" validate-email ng-model="email[$index]" ng-required="email.length==1 " name="email_{{$index}}" id="email_{{$index}}">
</div>
<button type="button" value="add" ng-click="add()">+</button>
</form>
</body>
</html>

Angular JS textarea validation with required & showing error message

I have a Angular JS code where i want to implement validation and focus on the field back if textarea is empty.
<form ng-submit="addComment()" role="form" name="blogForm" novalidate>
<div class="form-group" ng-class="{ 'has-error' : blogForm.blogComment.$invalid && replySubmitted }">
<textarea ng-model="blogComment" name="blogComment" class="form-control" rows="3" ng-required="true" required></textarea>
</div>
<div style="color:#a94442;" ng-show="blogForm.blogComment.$invalid && replySubmitted">
<span ng-show="blogForm.blogComment.$error.required">Comment Text required.</span>
</div>
<button type="submit" ng-click="replySubmitted = true" class="btn btn-primary blog-bubmit-button">Submit</button>
</form>
For some reasons the above code is just inserting empty data and field is focused Invalid.
Any Suggestions may help me.
Thanku
you have define ng-app to process it as angular block.
<script src="https://ajax.googleapis.com/ajax/libs/angularjs/1.2.23/angular.min.js"></script>
<div ng-app=''>
<form ng-submit="addComment()" role="form" name="blogForm" novalidate>
<div class="form-group" ng-class="{ 'has-error' : blogForm.blogComment.$invalid && replySubmitted }">
<textarea ng-model="blogComment" name="blogComment" class="form-control" rows="3" ng-required="true" required></textarea>
</div>
<div style="color:#a94442;" ng-show="blogForm.blogComment.$invalid && replySubmitted">
<span ng-show="blogForm.blogComment.$error.required">Comment Text required.</span>
</div>
<button type="submit" ng-click="replySubmitted = true" class="btn btn-primary blog-bubmit-button">Submit</button>
</form>
</div>

How to get input from user display in HTML page

I encounter a problem to display input from user into this table.
<tr ng-repeat="user in users" ng-class-even="'bg-light-grey'" ng-if="isLoading==false">
<td>
<div> {{user.username}} </div>
</td>
<td>
<div> {{user.name}} </div>
</td>
</tr>
If user click this "edit user" button, the form will appear.
<div class="glyphicon glyphicon-lock" ng-click="editUser();">
This is form that require user to fill edit their username and name
<div class="dialog-contents">
<div class="modal-header">
<button type="button" class="close" data-dismiss="modal">
<span aria-hidden="true">×</span>
<span class="sr-only">Close</span>
</button>
<h4 class="modal-title" id="myModalLabel">Edit User</h4>
</div>
<!-- Modal Body -->
<div class="modal-body">
<form name="edituser">
<div class="form-group has-feedback" ng-class="editUser.username.$valid ? 'has-success' : 'has-error';">
<label class="col-sm-2 control-label" for="Username">Username</label>
<div class="col-sm-10">
<input type="username" ng-model="user.username" class="form-control" id="Username" placeholder="Enter Username"/>
</div>
<span class="glyphicon form-control-feedback"
ng-class="addUser.username.$valid ? 'glyphicon-ok' : 'glyphicon-remove';"></span>
</div>
<div class="form-group has-feedback" ng-class="editUser.name.$valid ? 'has-success' : 'has-error';">
<label class="col-sm-2 control-label" for="Name">Name</label>
<div class="col-sm-10">
<input type="name" ng-model="user.name" class="form-control" id="name" placeholder="Enter Name"/>
</div>
<span class="glyphicon form-control-feedback"
ng-class="addUser.name.$valid ? 'glyphicon-ok' : 'glyphicon-remove';"></span>
</div>
Form this form, if user click this "submit" button, the user details will appear in table as i provide the code above.
<button type="submit" class="btn btn-primary" ng-click="add();"
ng-class="isLoading ? 'disabled' : '';">Submit </button>
Now, i want to push the input from user, and display it in the table. But i am stuck in developing the controller to get the input and displayed it. Appreciate if someone can help solve this problem.
app.register('user', ['$scope', 'ngDialog', function ($scope, $dialog) {
$scope.isLoading = false;
$scope.addUser = function(){
$dialog.open({
showClose: false,
closeByEscape: true,
template: 'view/user/user-user-add.html',
controller: ['$scope', function ($dialogScope) {
$dialogScope.users = {
username : "" ,
name : "",
status : "",
}
.closePromise.then(function (data)
$dialogScope.hasError = false;
$dialogScope.errorMessage = '';
$dialogScope.add=function(){
$dialogScope.closeThisDialog({username:"xxx"});
}
}]
});
};
}]);
In your add function, close the dialog and pass the new user object to close promise, like this: -
//your dialog controller
$dialogScope.add=function(){
$dialogScope.closeThisDialog({username:"xxx"});
};
you main controller: -
$scope.addUser = function(){
$dialog.open({
....
})
.closePromise.then(function (data) {
console.log(data);
//check and find user from the data and do what you need, i.e. $scope.users.push(user);
});
};

How to use ternary operator to change value of ng-model in AngularJS?

I have one text field and one checkbox. If checkbox is true I want value from address field to become after the checkbox, if false the field should be empty. I tried ternary operator with ng-class and many more, but no luck. What would be the best and working solution for that?
jsfiddle
<form name="form" ng-app>
<div class="form-group form-group-lg required">
<label class="col-md-2 control-label">Address:</label>
<div class="col-md-10" ">
<input type="text " name="address " class="form-control " ng-model="address " ng-minlength="4 " placeholder="Address " required>
</div>
</div>
<div class="form-group form-group-lg">
<label class="col-md-2 control-label">Return Address</label>
<div class="col-md-10">
<div class="input-group">
<span class="input-group-addon">
<!--condition ? first_expression : second_expression; -->
<input type="checkbox" ng-model="isReturnAddress" ng-change="">
</span><!--condition ? first_expression : second_expression; -->
<input type="text" class="form-control" ng-model="address">
</div>
{{isReturnAddress}}
</div>
</div>
<button type="submit " class="btn btn-primary btn-large " ng-click="submitted=true ">Submit</button>
you should use two input elements in this case. Like
<input ng-if="isReturnAddress" type="text" class="form-control" ng-model="address">
<input ng-if="!isReturnAddress" type="text" class="form-control">
and in your controller, please check
if($scope.isReturnAddress){
var address = $scope.address;
}
See working fiddle here

Is there a way to write these angular bindings more efficiently?

I have a form embedded in a view in my Angular JS 1.2.6 application.
<div class="container" ng-controller="LoginCtrl as signin">
<div class="row">
<div class="col-md-4">
<form name="signin.myForm" novalidate autocomplete="off">
<h1>Sign In</h1>
<div class="form-group" ng-class="{'has-error': (signin.myForm.name.$error.required || signin.myForm.name.$error.minlength) && signin.myForm.name.$dirty}">
<label>Name</label>
<input class="form-control" type="text" name="name" ng-model="signin.myForm.data.name" required ng-minlength="3">
<span class="help-block" ng-show="signin.myForm.name.$error.required && signin.myForm.name.$dirty" >Name is required.</span>
<span class="help-block" ng-show="signin.myForm.name.$error.minlength && signin.myForm.name.$dirty" >Must be at least 3 characters.</span>
</div>
<button class="btn btn-primary" ng-disabled="!signin.myForm.$valid" ng-click="signin.submit()">Sign in</button>
</form>
</div>
with the controller being:
app.controller('LoginCtrl', ['$log',function($log){
var ctrl = this;
ctrl.submit = function(){
console.log(ctrl.myForm);
if(ctrl.myForm.$valid){
console.log('the form is valid');
}
};
}]);
As you can see, to get the form field's data to be part of the same scope as the signin I was taught to first do ng-controller="LoginCtrl as signin" and then I wind up with convoluted names for models and properties like signin.myForm.name.$error.required
Is this the correct way to do it? It seems to work, but although I am a noob this seems like a bit tangled to me. Is this really the best practice?
I think it's more common to see something like this, where you attach things to an injected $scope instead of this, and then you don't have to put a namespace qualifier on the references in the HTML.
<div class="container" ng-controller="LoginCtrl">
<div class="row">
<div class="col-md-4">
<form name="myForm" novalidate autocomplete="off">
<h1>Sign In</h1>
<div class="form-group" ng-class="{'has-error': (myForm.name.$error.required || myForm.name.$error.minlength) && myForm.name.$dirty}">
<label>Name</label>
<input class="form-control" type="text" name="name" ng-model="signin.myForm.data.name" required ng-minlength="3">
<span class="help-block" ng-show="signin.myForm.name.$error.required && myForm.name.$dirty" >Name is required.</span>
<span class="help-block" ng-show="myForm.name.$error.minlength && myForm.name.$dirty" >Must be at least 3 characters.</span>
</div>
<button class="btn btn-primary" ng-disabled="!myForm.$valid" ng-click="submit()">Sign in</button>
</form>
</div>
app.controller('LoginCtrl', ['$scope', '$log',function($scope, $log){
$scope.submit = function(){
console.log($scope.myForm);
if($scope.myForm.$valid){
console.log('the form is valid');
}
};
}]);

Categories