ng-class not being applied when using setValidation() - angularjs

I have a login form that has required and email validation. If either of these validations fail, the error message is displayed and the error class is applied to the field.
These are applied as expected. When the user logs in, if the credentials fail, I want to manually add a validation error. This invalidates the form, and my message is displayed saying 'Email/password combination is not recognised', but the error class is not applied to the field - even though (loginForm.$submitted && !loginForm.email.$valid) evaluates to true.
What am I missing here?
js:
login() {
if (!this.$scope.loginForm.$valid) {
return;
}
this.authenticationService
.login(this.email, this.password)
.success((response) => {
//success code...
})
.error((response) => {
if (response.error === 'invalid_grant') {
this.$timeout(() => {
this.$scope.$apply(() => {
this.$scope.loginForm.email.$setValidity('invalidGrant', false);
});
});
}
});
}
html:
<form name="loginForm" ng-submit="loginController.login()" novalidate>
<input type="email" class="form-control" id="email" name="email" placeholder="Email" ng-model="loginController.email" required=""
ng-class="{error:loginForm.$submitted && !loginForm.email.$valid}" />
<div ng-show="loginForm.$submitted">
<span ng-show="loginForm.email.$error.required">Email field is required.</span>
<span ng-show="loginForm.email.$error.email">Email field is not valid.</span>
<span ng-show="loginForm.email.$error.invalidGrant">Email/password combination is not recognised.</span>
</div>
<!-- other fields... -->
<button type="submit">Sign In</button>
</form>

Related

posting data through angular form without page reload in angular

$scope.createPermission= function(form){
AppFactory.createNewPermission(form)
.success(function(data) {
$scope.updatedPermissions = data;
$scope.navMode='getPermission'
var original = $scope.permission;
$scope.reset(original);
$scope.permission = {}; // clear the form
})
.error(function(data) {
console.log('Error in creating permission: ' + data);
});
$scope.Execute=function(id) {
if($scope.navMode=='updatePermission') {
$scope.editPermission(id);
} else if($scope.navMode=='createPermission') {
$scope.createPermission($scope.permission);
}
}
}
$scope.reset= function(original) {
$scope.permission= angular.copy(original)
$scope.form2.$setPristine(true);
//$scope.form2.$setUntouched(true);
}
HTML:
<div class="row">
<div class="container col-sm-6 col-sm-offset-2"
ng-show="navMode == 'createPermission' || navMode=='updatePermission' || navMode=='getPermission'">
<div>
<h1>Permissions</h1>
</div>
</div>
<form class="form2" ng-show="showHide('Create')" ng-if=""name="form2" ng-submit="Execute(permissionId)" novalidate>
<div class="form-group" ng-class="{ 'has-success': form2.name.$valid && submitted, 'has-error': form2.name.$invalid && submitted }">
<label>Permission Name</label>
<input type="text" name="name" class="form-control" ng-model="permission.name" required/>
<p class="help-block" ng-show="form2.name.$error.required && submitted">
A permission name is required
</p>
</div>
<div class="row col-lg-offset-3">
<button class="btn btn-primary" ng-disabled="form2.$invalid" type="submit">Save</button>
</div>
</form>
</div>
I have above piece of code in controller and is executed on submission of the form. Now , It does work fine on page reload but I can not add data through form back to back. I need to reload teh page everytime to post new data through the form.
Why exactly is that ?
How do I fix this?
Without seeing the HTML part of this, I would guess you are using the action attribute of <form>. AngularJS provides ng-submit which allows you to set a handler for the submit event, without actually 'submitting' the form in the traditional sense. See https://docs.angularjs.org/api/ng/directive/ngSubmit.

In angularjs, how to set focus on input on form submit if input has error?

This is my code and I want to set focus on first name textbox on form submit if first name textbox has error like $error.required,$error.pattern,$error.minlength or $error.maxlength.
<form class="form-horizontal" name="clientForm" id="clientForm" novalidate ng-submit="clientForm.$valid" ng-class="{ loading:form.submitting }">
<div class="form-group">
<label class="col-lg-2 control-label">First Name</label>
<div class="col-lg-8">
<input type="text" ng-model="client.firstName" class="form-control" required autofocus name="firstName" autocomplete="off" ng-maxlength="100" ng-minlength=3 ng-pattern="/^[a-zA-Z]*$/" />
<!--<span ng-show="clientForm.firstName.$dirty && clientForm.firstName.$invalid" class="error">First Name is required.</span>-->
<div class="errors" ng-show="clientForm.$submitted || clientForm.firstName.$touched">
<div class="error" ng-show="clientForm.firstName.$error.required">
First Name is required.
</div>
<div class="error" ng-show="clientForm.firstName.$error.pattern">
Enter valid name.
</div>
<div class="error" ng-show="clientForm.firstName.$error.minlength">
First Name is required to be at least 3 characters
</div>
<div class="error" ng-show="clientForm.firstName.$error.maxlength">
First Name cannot be longer than 100 characters
</div>
</div>
</div>
</div>
<button type="submit" class="btn btn-primary">Save</button></form>
This question is a duplicate of:
Set focus on first invalid input in AngularJs form
You can use a directive on the form:
<form accessible-form>
...
</form>
app.directive('accessibleForm', function () {
return {
restrict: 'A',
link: function (scope, elem) {
// set up event handler on the form element
elem.on('submit', function () {
// find the first invalid element
var firstInvalid = elem[0].querySelector('.ng-invalid');
// if we find one, set focus
if (firstInvalid) {
firstInvalid.focus();
}
});
}
};
});
Here is a working Plunker:
http://plnkr.co/edit/wBFY9ZZRzLuDUi2SyErC?p=preview
You'll have to handle this using directive. For example:
It will iterate through the element(s) and check if the focusNow attribute is true or not. Make sure that the error handler code sets the expression true/false.
.directive('focusNow', function ($timeout) {
return {
link: function (scope, element, attrs) {
scope.$watch(attrs.focusNow, function (value) {
if (value === true) {
for (var i = 0; i < element.length; i++) {
var ele = angular.element(element[i].parentNode);
if (!ele.hasClass('ng-hide')) { //Skip those elements which are hidden.
element[i].focus();
}
}
}
});
}
};
});
and in the HTML, you'll have:
<input type="text" focus-now="expression" />
where expression will be a normal expression which will evaluate to true in case of error.
You can try this: i.e add ng-focus="clientForm.$error" in first name input
<input type="text" ng-focus="clientForm.$invalid" ng-model="client.firstName" class="form-control" required autofocus name="firstName" autocomplete="off" ng-maxlength="100" ng-minlength=3 ng-pattern="/^[a-zA-Z]*$/" />

better custom validation for angular form

I searched, I know 'the directive way' to do custom validation, but it looks like a overkill to me, I hope there is a simpler way, so I tried somwthing like this.
it works, but really not sure it is the right way(or angular way).
.controller('vali', ['$scope', function vali($scope) {
var th = this
th.formData = {}
// watch password repeat
$scope.$watch(function() {
return th.password1
}, function(newPass) {
if(!customValidate(newPass)) th.form.pass2.$setValidity('custom', false)
else th.form.pass2.$setValidity('custom', true)
})
//custom validate: password repeat must equal to password
function customValidate(v) {
if(v === th.formData.password) return true
else return false
}
this.submit = function(form) {
if(!th.form.$invalid) th.postToServer(th.formData)
}
this.postToServer = function(data) {
//do post to server
console.log(data)
}
}])
html:
<div ng-controller='vali as v'>
<form name='v.form' ng-submit='v.submit'>
<input type='password' name='pass1' ng-model='v.formData.password' minlength='6' />
<input type='password' name='pass2' ng-model='v.password1' />
<div ng-messages='v.form.pass2.$error' ng-if='v.form.pass2.$dirty'>
<div ng-message='required'>required</div>
<div ng-message='custom'> not equal</div>
</div>
<button type='submit'>submit</button>
</form>
</div>
You don't need to create your own directive for this. There is already a built-in directive for the password validation.
You can use that like this :
<input name="password" required ng-model="password">
<input name="confirm_password"
ui-validate=" '$value==password' "
ui-validate-watch=" 'password' ">
The input will be valid when the expression in ui-validate is true, so you can have any validation you want by changing the expression.

AngularJS form validations with submit and reset buttons

I have a simple form where I have applied AngularJS validation on a input box containing number value. On submit, it works fine but when I click on Reset button, it gives the input box validation error message. Looks like it is calling ng-submit after ng-click of Reset button. I have tried resetting the value of input field in ng-click, removed type='Reset' and also used $setPristine() on the form. But nothing helps. Below is the code.
<form name="myForm" novalidate ng-submit="submitFilter()">
Enter Age:
<div>
<input name="age" ng-class="{errorinput: submitted && myForm.age.$invalid }" class="form-control" ng-pattern="/^[0-9]+$/" placeholder="Age" type="text" ng-model="age" required>
</div>
<span class="error" ng-style="{color:'red'}" ng-show="submitted && myForm.age.$invalid">Please enter a valid Age</span>
<button type="submit">
Submit
</button>
<button ng-click="reset(myForm)">
Reset
</button>
</form>
Controller:
var original = $scope.age;
$scope.submitFilter = function () {
if ($scope.filterForm.$valid) {
} else {
$scope.submitted = true;
}
};
$scope.reset = function (myForm) {
$scope.age = angular.copy(original);
$scope.myForm.$setPristine();
};
Kindly help in getting rid of this error.
Thanks in Advance.
Setting the reset button's type as 'button' should work. Following code works perfectly on my machine.
// Code goes here
app.controller('mainController', function($scope) {
$scope.age = 123;
var original = $scope.age;
$scope.submitFilter = function () {
$scope.submitted = true;
};
$scope.reset = function (myForm) {
$scope.age = angular.copy(original);
$scope.myForm.$setPristine();
};
});
<form name="myForm" novalidate ng-submit="submitFilter()">
Enter Age:
<div>
<input name="age" ng-class="{errorinput: submitted && myForm.age.$invalid }" class="form-control" ng-pattern="/^[0-9]+$/" placeholder="Age" type="text" ng-model="age" required>
</div>
<span class="error" ng-style="{color:'red'}" ng-show="submitted && myForm.age.$invalid">Please enter a valid Age</span>
<button type="submit">
Submit
</button>
<button type="button" ng-click="reset(myForm)">
Reset
</button>
</form>

How do I unit test for form is/is not valid in Jasmine for AngularJS?

Given and AngularJS app with:
A form named 'LoginForm'
<div class="well well-large loginForm" ng-controller="LoginController" ng-hide="isAuthenticated">
<form id="loginForm" class="form-signin" name="LoginForm">
<h2 class="form-signin-heading">Please sign in</h2>
<input type="text" name="username" ng-model="user.username" required
class="input-block-level input-large" placeholder="Username" autocorrect="off" autocapitalize="off" tabindex="1">
<input type="password" name="password" ng-model="user.password" required
class="input-block-level input-large" placeholder="Password" tabindex="2">
<p ng-show="error401" class="text-error">Username and/or password was incorrect</p>
<p ng-show="error500" class="text-error">Whoops! Something went wrong</p>
<button class="btn btn-primary loginButton" ng-click="login(user)" tabindex="3">Sign in</button>
</form>
</div>
A controller named 'LoginController', with function of $scope.login()
$scope.login = function(user) {
if ($scope.LoginForm.$invalid) {
log('LoginForm is invalid');
return;
} else {
log('LoginForm is valid');
}
// ... snip ... other stuff like actual ajax login ...
}
How do I write a Jasmine test for $scope.LoginForm.$invalid?
I have found that it is a readonly property, so I tried to setup a mock object on $scope:
scope.LoginForm = {
"user" : {
"password": "something"
}
};
The above still passed validation, even though it should not have because both fields are required.
You could set the $invalid property to true in your unit test:
$scope.LoginForm.$invalid = true;

Resources