How can i write dynamic angularjs directive for validate? - angularjs

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>

Related

scope.$eval() is undefined if both input fields have the same directive

I'm trying to validate two password input fields. Simply confirm that they are equal. (Suggest another approach if mine is way wrong)
I have implemented a directive with a simple validation that checks if the "confirm" password is the same as the original. But the directive also checks for other things, so I need to have both input fields to have it.
The problem is that when I have my directive on both input fields, I cannot read their model values through the attribute (to check if they match).
Here is a working demo without the directive on the first password:
var app = angular.module('myApp', []);
app.controller('myCtrl', function($scope) {
});
app.directive('myDir', function() {
return {
require: 'ngModel',
link: function(scope, elem, attrs, ctrl) {
ctrl.$validators.mismatch = function(modelValue, viewValue) {
// MAIN CODE:
return viewValue === scope.$eval(attrs.confirm);
};
ctrl.$validators.short = function(modelValue, viewValue) {
if (ctrl.$isEmpty(modelValue)) {
return true;
}
if (modelValue.length >= 3) {
return true;
}
return false;
}
}
};
});
<script src="https://ajax.googleapis.com/ajax/libs/angularjs/1.5.7/angular.min.js"></script>
<div ng-app="myApp" ng-controller="myCtrl">
<form name="form1">
<input type="password" name="password1" ng-model="pass1"><br>
<input type="password" my-dir confirm="pass1" name="password2" ng-model="pass2"><br>
<pre>{{form1.password2.$error | json}}</pre>
<p ng-show="form1.password2.$error.mismatch" style="color:red">Passwords are different</p>
</form>
</div>
If I change the first filed to:
<input type="password" my-dir confirm="pass2" name="password1" ng-model="pass1">
to validate in both directions, then scope.$eval(attrs.confirm) becomes undefined for both fields.
Here is a demo of my issue:
var app = angular.module('myApp', []);
app.controller('myCtrl', function($scope) {
});
app.directive('myDir', function() {
return {
require: 'ngModel',
link: function(scope, elem, attrs, ctrl) {
ctrl.$validators.mismatch = function(modelValue, viewValue) {
// `scope.$eval(attrs.confirm)` always undefined
return viewValue === scope.$eval(attrs.confirm);
};
ctrl.$validators.short = function(modelValue, viewValue) {
if (ctrl.$isEmpty(modelValue)) {
return true;
}
if (modelValue.length >= 3) {
return true;
}
return false;
}
}
};
});
<script src="https://ajax.googleapis.com/ajax/libs/angularjs/1.5.7/angular.min.js"></script>
<div ng-app="myApp" ng-controller="myCtrl">
<form name="form1">
<input type="password" my-dir confirm="pass2" name="password1" ng-model="pass1"><br>
<input type="password" my-dir confirm="pass1" name="password2" ng-model="pass2"><br>
<pre>{{form1.password2.$error | json}}</pre>
<p ng-show="form1.password2.$error.mismatch || form1.password.$error.mismatch" style="color:red">
Passwords are different
</p>
</form>
</div>
You need to do 2 things:
1. Add ng-model-options="{allowInvalid: true}" so invalid value will still update scope value.
2. Now you have problem that e.g. changing 2nd input wont trigger 1st re-validation. This is done using observe:
<body ng-controller="MainCtrl" ng-init="x = 0; y = 0">
<form name="form1">
<input type="password" my-dir="{{y}}" confirm="pass2" name="password1" ng-model="pass1" ng-model-options="{allowInvalid: true}"
ng-change="x = x + 1"><br>
<input type="password" my-dir="{{x}}" confirm="pass1" name="password2" ng-model="pass2" ng-model-options="{allowInvalid: true}"
ng-change="y = y + 1"><br>
and
attrs.$observe('myDir', function() {
ctrl.$validate();
});
http://plnkr.co/edit/ws4tVWGXfFNR2yqLRJN7?p=preview
P.S. for usual fields I would write my-dir="{{pass1}}" and then no need in $eval and ng-change, but for passwords... not sure

How can I Upload two files using two different file input in Angular Js?

I am checking extension of files , using angular js , my html code is:
<input type="file" name="file" onchange=" angular.element(this).scope().selectFileforUpload(this.files) " required/>
<input type="button" value="Click" ng-click="click()" />
and angular controller code is :
$scope.verifiedFileType = function (file) {
var fileName = file.name;
var extension = (fileName.substring(fileName.lastIndexOf('.'), fileName.length)).toLowerCase();
if (extension === ".pdf") {
return true;
}
else {
return false;
}
};
$scope.click = function () {
if ($scope.verifiedFileType($scope.SelectedFileForUpload)) {
alert("Yes");
} else {
alert("No");
}
}
This works fine. But I want to check the extension of two files of two separete file inputs. I have tried this:
<input type="file" name="file" onchange=" angular.element(this).scope().selectFileforUpload(this.files) " required/>
<input type="file" name="file2" onchange=" angular.element(this).scope().selectFileforUpload(this.files) " required/>
<input type="button" value="Click" ng-click="click()" />
$scope.click = function () {
if ($scope.verifiedFileType($scope.SelectedFileForUpload[0]) && $scope.verifiedFileType($scope.SelectedFileForUpload[1])) {
alert("Yes");
} else {
alert("No");
}
}
But this code doesn't run. How can I perfom this task?
You can try below-given directive approach to achieve this.
Directive
app.directive('ngFileModel', ['$parse', function ($parse) {
return {
restrict: 'A',
link: function (scope, element, attrs) {
var validFormats = ['jpg'];
element.bind('change', function () {
var values = [];
angular.forEach(element[0].files, function (item) {
var fileName = item.name;
console.log(fileName);
let ext = fileName.substring(fileName.lastIndexOf('.') + 1).toLowerCase();
if(validFormats.indexOf(ext) == -1){
//Setup image upload logic here...
}
});
});
}
};
}]);
HTML
<body ng-controller="MainCtrl">
<input type="file" ng-file-model="files1" multiple />
<input type="file" ng-file-model="files" multiple />
</body>
Hope this will give you boost!

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">

Validation using custom directive with angularjs

I have a form with input fields and have a custom directive for each input field to validate the data entered by user.Requirement is that when user leaves the input field with invalid data, error message to be displayed.However, few of the fields are optional that if User skips with out entering any data for these fields, no Validation is required.
I tried to implement this using Blur event in the directive, but this is causing the vaidation called even in case of no data entered.
Please advise if Watch function can be used here and any sample snippet here would be appreciated. I have written code in a fiddle which is similar to my directive for one of the input field that checks minimum length (although there is a built-in directive, taken this as an example).This fiddle can be accessed at http://jsfiddle.net/4xbv0tgL/49/
<div ng-app="myApp" ng-controller="myCtrl">
<form name="myForm">
Num1: <input type="text" ng-model="num1" my-min-length="5" name="num1" />
<span class="error" ng-hide="myForm.num1.$valid"
ng-show="myForm.num1.$error">Invalid Number!</span>
<br />
Num2: <input type="text" ng-model="num2" my-min-length="5" name="num2" />
<span class="error" ng-hide="myForm.num2.$valid"
ng-show="myForm.num2.$error">Invalid Number!</span>
</form>
</div>
var myApp = angular.module("myApp", []);
var myCtrl = myApp.controller("myCtrl",["$scope", function($scope) {
$scope.num1 = "12345";
$scope.num2 = "55555";
}]);
myApp.directive("myMinLength", function () {
return {
restrict: "A",
require: "ngModel",
link: function (scope, element, attr, ngModelCtrl) {
var minlength = Number(attr.myMinLength);
var inputparse = function (inputtext) {
if ((inputtext.length >= minlength) && (!isNaN(inputtext))) {
return inputtext;
}
return undefined;
}
ngModelCtrl.$parsers.push(inputparse);
element.bind("blur", function () {
var value = inputparse(element.val());
var isValid = !!value;
if (isValid) {
ngModelCtrl.$setViewValue(value);
ngModelCtrl.$render();
}
ngModelCtrl.$setValidity("myMinLength", isValid);
scope.$apply();
}
);
}
};
});
I think you are over complicating life for yourself. Why don't you just use multiple directives for multiple checks?
<div ng-app="myApp"
ng-controller="myCtrl">
<form name="myForm"
novalidate>
Num1:
<input type="text"
ng-model="num1"
ng-minlength="5"
integer
name="num1"
required/>
<span class="error"
ng-show="myForm.num1.$invalid&&myForm.num1.$touched">Invalid Number!</span>
</form>
</div>
And here's the integer directive:
var INTEGER_REGEXP = /^[0-9]*$/;
myApp.directive('integer', function () {
return {
require: 'ngModel',
link: function (scope, elm, attrs, ctrl) {
ctrl.$parsers.unshift(function (viewValue) {
if (viewValue === "") {
ctrl.$setValidity('integer', true);
return viewValue;
} else if (INTEGER_REGEXP.test(viewValue)) {
ctrl.$setValidity('integer', true);
return viewValue;
} else {
ctrl.$setValidity('integer', false);
return viewValue;
}
});
}
};
});
Just be sure that you are using angular 1.3 or a newer version. Because $touched and $untouched don't exist in 1.2.

Angular setValidity not working?

I first using setValidity to make a directive in Angular.but not as my expected,here is my code:
angular.module('myApp', [])
.controller('ctrl',function($scope){
$scope.pw='';
})
.directive('pwCheck', function(){
return {
require: 'ngModel',
link: function (scope, elem, attrs, ctrl) {
elem.on('keyup', function () {
scope.$apply(function () {
var len = elem.val().length;
if(len===0){
ctrl.$setValidity('zero',true);
} else if(len>1 && len<6){
ctrl.$setValidity('one',true);
} else {
ctrl.$setValidity('two',true);
}
});
});
}
};
});
HTML:
<body ng-controller="ctrl">
<form id="myForm" name="myForm">
<input type="text" ng-model="pw" pw-check />
{{myForm.$error}}
<div class="msg-block" ng-show="myForm.$error">
<span class="msg-error" ng-show="myForm.pw.$error.zero">
Input a password.
</span>
<span class="msg-error" ng-show="myForm.pw.$error.one">
Passwords too short.
</span>
<span class="msg-error" ng-show="myForm.pw.$error.two">
Great.
</span>
</div>
</form>
</body>
Online Demo:
http://jsbin.com/cefecicu/1/edit
I think you need:
//Reset your validity
ctrl.$setValidity('zero',true);
ctrl.$setValidity('one',true);
ctrl.$setValidity('two',true);
if(len===0){
ctrl.$setValidity('zero',false);
} else if(len>=1 && len<6){ //use len>=1 instead
ctrl.$setValidity('one',false);
} else {
ctrl.$setValidity('two',false);
}
Using false to indicate errors (not valid):
And give a name to your input:
<input type="text" ng-model="pw" name="pw" pw-check />
http://jsbin.com/cefecicu/11/edit

Resources