Angular set pristine doesn't work as expected - angularjs

I am trying to create a custom validation on one of my inputs. Everything works as expected but the error css class is still applied. I tried with $setPristine()
and $setUntouched() first on the input (didn't work) and then on the form. The perfect solution will be if I can reset the style in ng-change.
self.changeTransferNumber = function () {
if (validateRoutingNumber(self.bankTransferNumber)) {
self.bankInfoForm.bankTransferNumber.$error.validateTransferNumber = false;
self.bankInfoForm.$setPristine();
self.bankInfoForm.$setUntouched();
} else {
self.bankInfoForm.bankTransferNumber.$error.validateTransferNumber = true;
}
}
<form name="$ctrl.bankInfoForm" novalidate ng-submit="$ctrl.saveInfo($event)">
<input type="text" ng-model="$ctrl.bankTransferNumber" ng-disabled="$ctrl.disableTextEdit" name="bankTransferNumber" required ng-change ="$ctrl.changeTransferNumber()"/>
<div ng-messages="$ctrl.bankInfoForm.bankTransferNumber.$error" ng-show="$ctrl.bankInfoForm.bankTransferNumber.$dirty">
<div ng-message = "validateTransferNumber" >The transfer number is not correct</div>
</div>
</form>

You need to pass your Form name in html:-
<form role="form" name="Form" id="Form" ng-submit="Form.$valid && saveFormData($event,Form)" novalidate autocomplete="off">
in Your controller /js file :-
$scope.saveFormData = function (event,myForm) {
//after your whole logic
....
//to reset form
myForm.$setPristine();
}
What i understand from this question....

Why not create a custom validator using a directive? This way it's easily reusable.
(function() {
'use strict';
angular.module('myApp', []);
angular.module('myApp').controller('MyController', MyController);
MyController.$inject = [];
function MyController() {
var main = this;
main.routingNumber = '2';
}
angular.module('myApp').directive('validateRoutingNumber', function() {
return {
restrict: 'A',
require: {ngModel: ''},
bindToController: true,
controllerAs: '$dir',
controller: function() {
var $dir = this;
$dir.$onInit = function() {
createValidators();
};
function createValidators() {
$dir.ngModel.$validators.routingNumber = function(modelValue, viewValue) {
var value = modelValue || viewValue;
//without this if-else it would become a required field
if (value) {
return value.toString().length >= 3 && value.toString().indexOf('1') !== -1;
} else {
return true;
}
}
}
}
};
});
}());
input.ng-invalid {
border: 1px red solid;
background-color: red;
color: white;
}
<script src="https://ajax.googleapis.com/ajax/libs/angularjs/1.5.8/angular.min.js"></script>
<body ng-app="myApp">
<div ng-controller="MyController as main">
<form name="frmMain">
<input type="text" ng-model="main.routingNumber" name="routingNumber" validate-routing-number>
<span ng-if="frmMain.routingNumber.$invalid">Needs to have at least three characters and at least one '1'</span>
</form>
</div>
</body>

Related

Disable and empty model value and then restore it

I have working code:
<input type="checkbox" ng-model="disabled" >
<input type="text" ng-model="text" ng-disabled="disabled">
When disabled == true the input is disabled. I need to hide actual model value (set empty) as well. And after uncheck the checkbox actual model value should appears. How to do it without changing model value?
I would do something like this:
<input type="checkbox" ng-model="disabled" ng-change="change()">
<input type="text" ng-model="text" ng-disabled="disabled">
...
$scope.change = function() {
if ($scope.disabled) {
$scope.textBackup = $scope.text;
$scope.text = '';
} else {
$scope.text = $scope.textBackup;
}
};
Note: I posted before reading #AbdulMateenMohammed comment... My answer is an implementation of his suggestion...
This is not the best option but if you want to deal only with the view:
<input type="checkbox" ng-model="disabled">
<div ng-show="disabled">
<input type="text" ng-init="text2 = ''" ng-model="text2" ng-disabled="true">
</div>
<div ng-hide="disabled">
<input type="text" ng-model="text">
</div>
Again, this is not the best option!!! MarcosS option is the recommended.
#Makarov Sergey, I think even when you have a complex view or data source the basic idea is to use a temporary variable because you need to have two values b/w which you swap around.
angular
.module('demo', [])
.controller('DefaultController', DefaultController);
function DefaultController() {
var originalText = '';
var vm = this;
vm.text = 'Hello, World!';
vm.onValueChanged = onValueChanged;
function onValueChanged(text) {
if (vm.disabled) {
originalText = text;
vm.text = '';
} else {
vm.text = originalText;
}
}
}
span {
color: red;
}
<script src="https://ajax.googleapis.com/ajax/libs/angularjs/1.2.23/angular.min.js"></script>
<div>
<em>I </em><span>♥ </span><em>AngularJS</em>
</div>
<div ng-app="demo">
<div ng-controller="DefaultController as ctrl">
<input type="checkbox" ng-model="ctrl.disabled" ng-change="ctrl.onValueChanged(ctrl.text)"/>
<input type="text" ng-model="ctrl.text" ng-disabled="ctrl.disabled"/>
</div>
</div>
Tip: For the objects that aren't displayed in the view but present in the controller shouldn't be assigned on the scope because using scope would add some JavaScript events to do the data-binding which is unnecessary overhead such as the dirty check event for the two-way data-binding so that's why in the sample code snippet I used var originalText = ''; instead of vm.originalText = '';
Found the solution that works for me atm
function directive() {
return {
restrict: 'A',
require: 'ngModel',
link: function (scope, element, attrs, ngModelCtrl) {
let oldViewValue = '';
scope.$watch(() => attrs.hideValue, (newV) => {
if (newV == 'true') {
oldViewValue = ngModelCtrl.$viewValue;
ngModelCtrl.$viewValue = '';
} else {
ngModelCtrl.$viewValue = oldViewValue;
}
ngModelCtrl.$render();
});
}
}
}
And use:
<input type="checkbox" ng-model="disabled" >
<input type="text" ng-model="text" ng-disabled="disabled" hide-value="disabled">

How can i write dynamic angularjs directive for validate?

I am newbie in angularjs, and I have a question.
I want to write only a directive for validate all types data (string, number,etc).
I wrote in JSFIDDLE,you can visit here: http://jsfiddle.net/wk8rbot5/5/, it worked.
But I dont want to use if-else to much in this file. I think we can use type or regex from other file. So anyone has suggestion, please let me know. Thank you so much.
var app = angular.module("app",[]);
app.controller("FormCtrl", function($scope) {
$scope.data = {};
$scope.action = function() {
debugger
console.log($scope.data);
}
});
app.directive("allowPattern", function() {
return {
restrict: "A",
require: "ngModel",
link: function(scope, el, attrs, ngModel) {
var validator, patternValidator,
validType = attrs.allowPattern,
required = true;
var pattern = "";
if( validType =="email" ) {
pattern = new RegExp(/^[A-Za-z0-9_-]+([\.]?[A-Za-z0-9_-])*#\w+([-.]\w+)*\.\w+([-.]\w+)*$/);
}
else if(validType =="onlynumber"){
//do other validate here
pattern = new RegExp(/^[0-9]*$/);
} else{
parttern = new RegExp(/^.*S/); // !!! SyntaxError is fixed in this line
}
patternValidator = function(value) {
return validate(pattern, value)
};
ngModel.$formatters.push(patternValidator);
ngModel.$parsers.push(patternValidator);
attrs.$observe("required", function(newval) {
required = newval;
patternValidator(ngModel.$viewValue);
});
function validate(regexp, value) {
if( value == null || value === "" || !required || regexp.test(value) ) { // !!! TypeError: regexp.test is not a function
ngModel.$setValidity('pattern', true);
return value;
}
else {
ngModel.$setValidity('pattern', false);
return;
}
}
}
};
});
<script src="//ajax.googleapis.com/ajax/libs/angularjs/1.5.6/angular.min.js"></script>
<div ng-app="app" ng-controller="FormCtrl">
<form name="theForm" novalidate="novalidate">
<input type="text" ng-model="data.name" allow-pattern="email" required/>
<button ng-disabled="theForm.$invalid" ng-click="action()">Action</button>
</form>
<br>
other form:
<br>
<form name="theForm2" novalidate="novalidate">
<input type="text" ng-model="data.number" allow-pattern="onlynumber" required/>
<button ng-disabled="theForm2.$invalid" ng-click="action2()">Action</button>
</form>
<br>
other form 3 :
<br>
<form name="theForm3" novalidate="novalidate">
<input type="text" ng-model="data.abc" allow-pattern="" required/>
<button ng-disabled="theForm3.$invalid" ng-click="action3()">Action</button>
</form>
</div>

AngularJS - write custom directive to validate passed values

I have an html form that looks like this :
<div class="row col-lg-offset-3">
<div class="form-group col-lg-6" ng-class="{ 'has-error': userForm.Age.$invalid && userForm.Age.$dirty}" show-errors >
<label class="control-label">Age</label>
<input type="text" class="form-control" name="Age" ng-model="user.Age" ng-required='!user.phonenumber' placeholder="Age"/>
</div>
</div>
Directive:
(function(){
angular.module('myApp', [])
.controller('studentDataController', function($scope) {})
.directive('showErrors', function() {
return {
restrict: 'A',
require: '^form',
link: function (scope, el, attrs, formCtrl) {
var inputEl = el[0].querySelector("[Age]");
var inputNgEl = angular.element(inputEl);
var inputValue = inputNgEl.attr('Age');
var isValid = (inputValue >= 3 && inputValue < 100);
inputNgEl.bind('blur', function() {
el.toggleClass('has-error', isValid);
})
}
}
});
})();
I am trying to validate input for Age field when it blurs out.Age value should be between 3 to 99.i.i.e check if the value is valid or invalid when user is done typing and leaves the text field.Then if the value is invalid, apply the has- class
The directive though is not working. Did I miss anything ?
If really have to do that via custom directive please see below:
var app = angular.module('app', []);
app.controller('MainCtrl', function($scope) {
$scope.name = 'World';
});
app
.directive('ngAge', NgLength);
function NgLength() {
return {
restrict: 'A',
require: 'ngModel',
link: function($scope, $element, $attrs, ngModel) {
$scope.$watch($attrs.ngModel, function(value) {
var isValid = (value > 3 && value < 100);
ngModel.$setValidity($attrs.ngModel, isValid);
});
}
}
}
/* Put your css in here */
.has-error {
background-color: red;
}
<script src="https://ajax.googleapis.com/ajax/libs/angularjs/1.2.23/angular.min.js"></script>
<body ng-app="app">
<form name="userForm" ng-class="{ 'has-error': userForm.Age.$invalid && userForm.Age.$dirty}">
<label class="control-label">Age</label>
<input type="text" class="form-control" name="Age" ng-model="user.Age" ng-age placeholder="Age" />
</form>
</body>
AngularJS 1.3.x introduces $validators pipeline - it is much simpler to write custom validation rules with them.
A collection of validators that are applied whenever the model value changes. The key value within the object refers to the name of the validator while the function refers to the validation operation. The validation operation is provided with the model value as an argument and must return a true or false value depending on the response of that validation.
var app = angular.module('app', []);
app
.controller('MainCtrl', function($scope) {
$scope.name = 'World';
}).directive('ngAge', function NgLength() {
return {
restrict: 'A',
require: 'ngModel',
link: function($scope, $element, $attrs, ngModel) {
ngModel.$validators.validAge = function(modelValue, viewValue) {
var age = modelValue || viewValue;
return age > 3 && age < 100
};
}
}
});
.has-error {
background-color: red;
}
<script src="https://ajax.googleapis.com/ajax/libs/angularjs/1.3.0/angular.min.js"></script>
<body ng-app="app">
<form name="userForm" ng-class="{ 'has-error': userForm.Age.$invalid && userForm.Age.$dirty}">
<label class="control-label">Age</label>
<input type="text" class="form-control" name="Age" ng-model="user.Age" ng-age placeholder="Age" />
</form>
</body>
You can use max, min directive. Please sample below
var app = angular.module('plunker', []);
.has-error {
background-color:red;
}
<script src="https://ajax.googleapis.com/ajax/libs/angularjs/1.2.23/angular.min.js"></script>
<link data-require="bootstrap-css#*" data-semver="3.3.1" rel="stylesheet" href="//maxcdn.bootstrapcdn.com/bootstrap/3.3.1/css/bootstrap.min.css" />
<html ng-app="plunker">
<body>
<div class="row col-lg-offset-3">
<form name="userForm" class="form-group col-lg-6" ng-class="{ 'has-error': userForm.Age.$invalid && userForm.Age.$dirty}" show-errors>
<label class="control-label">Age</label>
<input type="number" class="form-control" name="Age" ng-model="user.Age" ng-required='!user.phonenumber' placeholder="Age" max="100" min="3" />
</form>
</div>

Directive-validator doesn't catch empty field but filled field

I have the following AngularJS code. It should check if input field is empty when I press Submit button. Submit button broadcasts custom event that directive successfully catches. But it doesn't work when field is empty. It reaches ctrl.$parsers.unshift when I start typing and my field becomes theForm.name.$invalid===true. It seems to work the opposite way.
define(['angular'], function (angular) {
"use strict";
var requiredValidator = angular.module('RequiredValidator', []);
requiredValidator.directive('validateRequired', function () {
var KEY_ERROR = "required";
return {
scope: {
validateRequired: '=validateRequired'
},
require: 'ngModel',
link: function (scope, elem, attr, ctrl) {
function validate(value) {
var valid = !value || value === '' || value === null;
ctrl.$setValidity(KEY_ERROR, valid);
return value;
}
scope.$on('validateEvent', function (event, data) {
if (scope.validateRequired.$submitted) {
console.log("Reachable block when submitted");
ctrl.$parsers.unshift(function (value) {
console.log("Unreachable when input is empty");
return validate(value);
});
ctrl.$formatters.unshift(function (value) {
return validate(value);
});
}
});
}
};
});
return requiredValidator;
});
Form field snippet:
<div>
<input type="text" name="name"
data-ng-class="{ error : theForm.name.$invalid}"
data-ng-model="customer.name"
data-validate-required="theForm">
<span data-ng-show="theForm.name.$invalid" class="error">{{getInputErrorMessage(theForm.name.$error)}}</span>
</div>
You actually don't need such a complex directive for your szenario. You could also handle the logic within a controller like so:
var app = angular.module('form-example', ['ngMessages']);
app.controller('FormCtrl', function($scope) {
var vm = this;
vm.submit = function(form) {
if (form.$invalid) {
angular.forEach(form.$error.required, function(item) {
item.$dirty = true;
});
form.$submitted = false;
} else {
alert('Form submitted!');
}
};
});
label,
button {
display: block;
}
input {
margin: 5px 0;
}
button {
margin-top: 10px;
}
form {
margin: 10px;
}
div[ng-message] {
margin-bottom: 10px;
color: red;
}
<script src="https://ajax.googleapis.com/ajax/libs/angularjs/1.3.15/angular.min.js"></script>
<script src="https://cdnjs.cloudflare.com/ajax/libs/angular.js/1.3.15/angular-messages.js"></script>
<form ng-app="form-example" name="myForm" ng-controller="FormCtrl as vm" novalidate="" ng-submit="vm.submit(myForm)">
<label for="username">Username</label>
<input id="username" type="text" name="username" ng-model="vm.username" required="" />
<div ng-messages="myForm.username.$error" ng-if="myForm.username.$dirty" role="alert">
<div ng-message="required">Username is required</div>
</div>
<label for="email">E-Mail</label>
<input id="email" type="email" name="email" ng-model="vm.email" required="" />
<div ng-messages="myForm.email.$error" ng-if="myForm.email.$dirty" role="alert">
<div ng-message="required">E-Mail is required</div>
<div ng-message="email">Your E-Mail is not valid</div>
</div>
<button type="submit">Send</button>
</form>
This requires to use at least AngularJS version 1.3.0 since I use the $submitted property of the internal FormController. For more information check the documentation on the FormController. I also use ngMessages which was also introduced in 1.3. This is pretty helpful if you want to display messages in forms in respect to errors.

Reset Validity of ngModel

Recently, I had a problem with Angular form validity. I easy can to add the entry to Array with help ngModel.$setValidity, but I can't to remove it after. My html tag has a lot of valid/invalid classes. I'd tried to do the form to pristine. But it does't work. How that things to do generally? Help me please! (Sorry for my english =) if I've made a mistake somewhere.)
It's not terribly well documented, but you can actually pass in null to the $setValidity() function in order to completely clear a validation flag.
If you want to set it to be valid then simply pass in true
//Reset validity for this control
this.form.firstName.$setValidity('someValidator', null);
//Or set to valid
this.form.firstName.$setValidity('someValidator', true);
And here is a running snippet to demonstrate this technique.
(function() {
'use strict';
function MainCtrl() {
this.firstName = 'Josh';
}
MainCtrl.prototype = {
setInvalid: function(ctrl) {
ctrl.$setValidity('customValidator', false);
},
setPristine: function(ctrl) {
ctrl.$setValidity('customValidator', null);
},
};
angular.module('sample', [])
.controller('MainCtrl', MainCtrl);
}());
<script src="https://ajax.googleapis.com/ajax/libs/angularjs/1.3.15/angular.min.js"></script>
<link href="https://maxcdn.bootstrapcdn.com/bootstrap/3.3.4/css/bootstrap.min.css" rel="stylesheet" />
<div class="container" ng-app="sample" ng-controller="MainCtrl as ctrl">
<div class="row">
<div class="col-sm-12">
<form name="ctrl.form">
<div class="form-group" ng-class="{'has-error':ctrl.form.firstName.$invalid}">
<label class="control-label">First Name</label>
<input type="text" class="form-control" name="firstName" ng-model="ctrl.firstName" />
</div>
<button type="button" class="btn btn-danger" ng-click="ctrl.setInvalid(ctrl.form.firstName)">Set Invalid</button>
<button type="button" class="btn btn-success" ng-click="ctrl.setPristine(ctrl.form.firstName)">Set Valid</button>
</form>
</div>
</div>
</div>
(function () {
angular.module("App")
.directive("password", password);
function password() {
var lastTrueRegex = {};
var regexes = {
week: /(?=^.{8,}$).*$/,
pettyWeek: /(?=^.{8,}$)(?=.*\d).*$/,
normal: /(?=^.{8,}$)(?=.*\d)(?=.*[a-z]).*$/,
prettyStrong: /(?=^.{8,}$)(?=.*\d)(?=.*[a-z])(?=.*[A-Z]).*$/,
strong: /(?=^.{8,}$)(?=.*\d)(?=.*[a-z])(?=.*[A-Z])(?![.\n]).*$/,
veryStrong: /(?=^.{8,}$)(?=.*\d)(?=.*[a-z])(?=.*[A-Z])(?![.\n])(?=.*[!##$%^&*]+).*$/
};
function forEach(data, callback) {
for (var key in data) {
if (data.hasOwnProperty(key)) {
callback(key, data[key]);
}
}
}
return {
require: "ngModel",
restrict: 'EA',
link: function (scope, element, attributes, ngModel) {
ngModel.$parsers.unshift(function (textValue) {
forEach(regexes, function (key, regex) {
if (regex.test(textValue)){
lastTrueRegex.name = key;
lastTrueRegex.value = true;
}else{
ngModel.$setValidity(key, null);
}
});
if (lastTrueRegex.name){
ngModel.$setValidity(lastTrueRegex.name, lastTrueRegex.value);
return textValue;
}
});
ngModel.$formatters.unshift(function (modelValue) {
//ngModel.$setValidity('strongPass', isValid(modelValue));
return modelValue;
});
}
};
}
})();
<form name="myForm">
<input type="text" name="password" ng-model="textValue" password/>
</form>

Resources