Custom directive for form validation - angularjs

I am trying to validate a number according to its min and max value through angularJS
this is the custom directive, I first tried with max that provide angularJs for input number validation it works with static number not with binding data. That's why i thought about custom directive
.directive('ngMax', function() {
return {
restrict: 'A',
require: 'ngModel',
link: function(scope, elem, attr, ctrl) {
scope.$watch(attr.ngMax, function(){
if (ctrl.$isDirty) ctrl.$setViewValue(ctrl.$viewValue);
});
var maxValidator = function(value) {
var max = scope.$eval(attr.ngMax) || Infinity;
if (!isEmpty(value) && value > max) {
ctrl.$setValidity('ngMax', false);
return undefined;
} else {
ctrl.$setValidity('ngMax', true);
return value;
}
};
ctrl.$parsers.push(maxValidator);
ctrl.$formatters.push(maxValidator);
}
};
});
and in the view :
<div class="modal-body" >
title: {{book.title}}<br>
price: {{book.price}}<br>
quantity: {{book.nbr_exemplaires}}
<form name= "myForm" ng-submit= "addToCart(book, quantity, <%= current_user.id %>)" novalidate >
<input type="number" min="1" ng-max="{{book.nbr_exemplaires}}" name= "quantite" ng-model="quantity" required >
<span style="color:red" ng-show="myForm.quantite.$error.required">
<span ng-show="myForm.quantite.$error.required">quantity is required!</span>
</span>
</div>
<div class="modal-footer">
<button type="button" class="btn btn-default" data-dismiss="modal">Close</button>
<button class="btn btn-primary" ng-disabled="myForm.$invalid ">Save changes</button>
</div>
</form>
I could not understand where is the problem

To avoid X/Y questions, when you try something and it doesn't work, try to address that first. That's good that you provided a broader context, so specifically to your question, built-in max provides everything that you need:
<input type="number" max="{{max}}" ng-model="foo">
and you can set max dynamically, for example:
$scope.max = 10;

Related

How can I return the required message without the distinct message?

I have a small password form that returns different messages depending on what has been entered, if nothing has been entered the message should just be "please enter a password" if the password entered is like the username then the only error message back should be "Your password can not be like your username". And finally when the pattern doesnt match the user should get a message about the pattern. When I enter nothing and click submit I am getting both the distinct and required messages back, how can I fix this to only show the required message until data has been entered that matches the username?
HTML:
<div ng-controller="NewPasswordCtrl" ng-init="init()">
<form name="npForm" class="col-md-12" role="form" style="padding-top:15px" ng-submit="SubmitPasswordReset(npForm, NewPasswordModel)" novalidate>
<div class="form-group">
<div class="input-group">
<input id="newPassword" name="newPassword" type="password" placeholder="Password" class="form-control" ng-model="NewPasswordModel.Password" ng-model-options="{ allowInvalid: true}" override-password user="{{NewPasswordModel.Username}}" ng-style="npForm.newPassword.$error.pattern && {'border':'1px solid red'}"
required>
<small id="newPasswordHelpBlock0" class="form-text text-danger" ng-if="npForm.newPassword.$error.required && npForm.$submitted">
Please enter a password.
</small>
<small id="newPasswordHelpBlock1" class="form-text text-danger" ng-if="npForm.newPassword.$error.pattern && npForm.$submitted">
Password is not valid. Password must be at least 8 characters, upper and lower case text, contain at least one number and contain at least one special character.
</small>
<small id="newPasswordHelpBlock2" class="form-text text-danger" ng-if="npForm.newPassword.$error.distinct && npForm.$submitted">
Your password can not be like your username.
</small>
</div>
</div>
<div class="form-group">
<div class="ml-5">
<button type="submit" class="btn btn-primary">Submit</button>
</div>
</div>
<hr /> model = {{NewPasswordModel}}
</form>
</div>
AngularJS
var app = angular.module('app', []);
app.controller('NewPasswordCtrl', ['$scope', function($scope) {
$scope.NewPasswordModel = {};
$scope.NewPasswordModel.Password = "";
$scope.init = function() {
$scope.NewPasswordModel.Username = 'Tester'
};
$scope.SubmitPasswordReset = function (form, model) {
if (form.$valid) {};
};
}]);
app.directive('overridePassword', function() {
var PASSWORD_REGEXP = /(?=.*[a-z])(?=.*[A-Z])(?=.*[0-9])(?=.*[$#$!%*?&])[A-Za-z\d$#$!%*?&].{7,}/;
return {
require: 'ngModel',
link: function(scope, elem, attrs, ctrl) {
var usr = attrs.user;
//For DOM -> model validation
ctrl.$parsers.unshift(function(modelValue) {
var valid = modelValue.includes(usr);
ctrl.$setValidity('distinct', valid);
return valid ? modelValue : undefined;
});
//For model -> DOM validation
ctrl.$formatters.unshift(function(modelValue) {
ctrl.$setValidity('distinct', modelValue.includes(usr));
return modelValue;
});
}
};
});
https://jsfiddle.net/devnsyde/q8v1b4Lj/
You can add another && condition to your ngIf directive that checks the length of your password input.
ng-if="npForm.newPassword.$error.distinct && npForm.$submitted && NewPasswordModel.Password.length > 0"
Demo

How to set maxlength for Ionic 1 input type?

The maxlength HTML5 attribute is not working properly on mobile for text input fields. If the number keypad is enabled it works, but it doesn't work when using text keypad.
Code:
<ion-content class="p-l-10 p-r-10 had-header form_page">
<form ng-submit="vm.addAdvance()">
<div class="list">
<label class="item item-input InputFormFull">
<span class="input-label">{{'note_message' | translate}}</span>
<input type="text" placeholder="{{'notes_message' | translate}}"
ng-model="vm.advance.description" id="field2" ng-change="vm.fillStarted()" size="5" maxlength="5" required>
</label>
<button class="button trans-but m-t-10" type="submit">{{'save_message' | translate}}</button>
</div>
</form>
Possible duplicate: Input maxlength does not work on Android -Ionic
Try creating your own directive:
myApp.directive('limitChar', function() {
'use strict';
return {
restrict: 'A',
scope: {
limit: '=limit',
ngModel: '=ngModel'
},
link: function(scope) {
scope.$watch('ngModel', function(newValue, oldValue) {
if (newValue) {
var length = newValue.toString().length;
if (length > scope.limit) {
scope.ngModel = oldValue;
}
}
});
}
};
})
Html:
<input type="text" limit-char limit="5">

File name doesn't get cleared after form.$setPristine for a custom angular directive for file upload

I am using angular 1.5.8. After following some resources, I got the file upload working. I had to create a custom directive for that.
Directive
//file-upload-model-directive.js
'use strict';
export default function (app) {
app.directive('fileUploadModel', fileUploadModelDirective);
function fileUploadModelDirective () {
'ngInject';
return {
restrict: 'A',
link: linkFn,
require: 'ngModel'
};
function linkFn (scope, element, attrs, ngModel) {
element.bind('change', function(event){
var files = event.target.files;
var file = files[0];
ngModel.$setViewValue(file);
scope.$apply();
});
}
}
}
I am also using angular's form. And I have a "reset" button on this form. I want to clear all the form fields when clicked. And it happens with all form fields except file.
View
<form ng-submit="dataCtrl.upload(form)" name="form">
<div class="form-group" ng-class="{'has-error' : form.file.$invalid && !form.file.$pristine}">
<label>Select file</label>
<input type="file" name="file" ng-model="dataCtrl.newUpload.csvFile" file-upload-model required/>
</div>
<div class="form-group" ng-class="{'has-error' : form.comment.$invalid && !form.comment.$pristine}">
<label>Comment</label>
<textarea class="form-control" name="comment"
ng-model="dataCtrl.newUpload.comment" required></textarea>
</div>
<div class="form-group pull-right">
<button type="submit" class="btn btn-success" ng-disabled="form.$invalid">Upload</button>
<button class="btn btn-default" ng-click="dataCtrl.reset(form)" ng-disabled="!form.$dirty">Reset</button>
</div>
</form>
And the Controller
'use strict';
function DataController($log, catalogCnst, requestSV, $http) {
'ngInject';
this.reset = function(form) {
this.newUpload = {};
// form.file.$setViewValue(null); // this didn't work either
form.$setPristine()
};
this.upload = function(form) {
// some code
};
}
When "reset" is clicked, I see that
form.file.$pristine is false
form.file.$invalid is false
But I still see filename near the file upload element.
I also tried adding watch and handling event on the element in the directive
scope.$watch(attrs.fileUploadModel, function(value) {
console.log('attrs.file');
});
element.on('$pristine', function() {
console.log('destroy');
});
But they didn't get invoked.
How do I do this? Please guide me.
When you clear newUpload, file input does not get cleared. You need to do this separately.
See JSFiddle:
Basically, I added to the directive scope:
scope: {
model: '=ngModel'
},
... and watch:
scope.$watch('model', function(file) {
if (!file) {
element.val('');
}
});
Instead of using button tags, why not use input tags. This, in theory, might work.
<input type="submit" class="btn btn-success" ng-disabled="form.$invalid" value="Upload">
<input type="reset" class="btn btn-default" ng-click="dataCtrl.reset(form)" ng-disabled="!form.$dirty" value="Reset">

Form Validation not working with ui-boostrap

I'm having a bit of trouble getting the form to run it's validation function. I have a plnkr. I Know I'm close... The validation file is loading in without errors. It's just not running the validation part. I built it off of this. What am I missing? Thanks in advance for the help.
my Form:
<form id="phone" class="content-pad span6" novalidate>
<div class="control-group" ng-class="{error:!input-form-Phone.phonenumber.$valid}">
<label for="phonenumber">Enter Area Code and Telephone Number</label>
<div class="form-group controls">
<input type="text" class="form-control" id="inputphonenumber" name="phonenumber" ng-model="phonenumber"
placeholder="Ex: 4155551234" valid-phonenumber/>
<div class="help-inline">
<span ng-show="!!phone.phonenumber.$error.isBlank">Phone Number Required.</span>
<span ng-show="!!phone.phonenumber.$error.invalidChars">Must Contain Number Only</span>
<span ng-show="!!phone.phonenumber.$error.invalidLen">Phone Number Must Contain area Code and Phone Number.</span>
</div>
</div>
</div>
<div class="form-actions" ng-show="formAllGood()">
<div class="span6">
<a ng-href="SA_report_results.html" class="btn btn-primary " type="button">Run Report</a>
</div>
</div>
<div class="span3" >
<input type="button" value="Reset" ng-click="reloadPage()" class="btn btn-danger "/>
</div>
</form>
app,js
var app = angular.module('myApp', ['myApp.formValidation','ui.bootstrap']);
app.controller('MainCtrl', function($scope) {
$scope.name = 'World';
$scope.formAllGood = function(){
return ($scope.phonenumberGood);
};
});
validation,js
angular.module('myApp.formValidation', [])
.directive('validPhoneNumber', function () {
return {
require: 'ngModel',
link: function (scope, elm, attrs, ctrl) {
ctrl.$parsers.unshift(function (viewValue) {
// Any way to read the results of a "required" angular validator here?
var isBlank = viewValue === '';
var invalidChars = !isBlank && !/^[A-z]+$/.test(viewValue);
var invalidLen = !isBlank && !invalidChars && (viewValue.length < 5 || viewValue.length > 20);
ctrl.$setValidity('isBlank', !isBlank);
ctrl.$setValidity('invalidChars', !invalidChars);
ctrl.$setValidity('invalidLen', !invalidLen);
scope.phonenumberGood = !isBlank && !invalidChars && !invalidLen;
});
}
};
});
You are calling valid-phonenumber which doesn't exist. It is valid-phone-number. This will make your plunker run.
By the way your invalidChars check is wrong.

cursor moves to new generated textbox in angualarjs

I have form with modal, When i click enter or add email button it generates the new text box but cursor will not move into that text box.
But i need when i click enter or add email button, then cursor automatically should move to the newly generated text box.
My html code
<script type="text/ng-template" id="myModalContent">
<div class="modal-header">
<h3 class="modal-title">I'm a modal!</h3>
</div>
<div class="modal-body">
<li ng-repeat="item in items " ng-form="subForm">
<input type="text" name="name" ng-model="item.email" required ng-pattern="/^[_a-z0-9]+(\.[_a-z0-9]+)*#[a-z0-9-]+(\.[a-z0-9-]+)*(\.[a-z]{2,4})$/" ng-enter="addOrRemove($index,item.email)"/>
<span ng-show="subForm.name.$error.required" style="color: red">Email required</span>
<span ng-show="subForm.name.$invalid" ng-hide="subForm.name.$error.required" style="color: red">Invalid email</span>
<button ng-disabled="subForm.name.$invalid || subFform.name.$dirty" ng-click="addOrRemove($index,item.email)" >{{item.value}}</button>
expression: {{subForm.name.$invalid}}
</li>
</div>
<div class="modal-footer">
<button class="btn btn-primary" ng-click="ok()">OK</button>
<button class="btn btn-warning" ng-click="cancel()">Cancel</button>
</div>
</script>
My javascript code
$scope.addOrRemove = function(indexSelected,rcvEmail)
{//alert($rootScope.email1);
if(!rcvEmail)
{
return
}
console.log("just check email",rcvEmail);
console.log("length of the object",$scope.items.length);
event.preventDefault();
if($scope.items[indexSelected].state == 1)
{
//console.log($scope.items[indexSelected].state);
$scope.items[indexSelected].value = "Remove email";
$scope.items[indexSelected].state = "0";
$scope.items[indexSelected].email = rcvEmail;
$scope.items.push({value: "Add email", state: "1"});
}
else
{
//console.log($scope.items[indexSelected].state);
//$scope.items.push({value: "Remove email", state: "1"});
$scope.items.splice(indexSelected, 1);
}
};
see the code here
In order to focus an input you have to create custom directive.
.directive('focus', function($timeout, $parse) {
return {
restrict: 'A',
link: function(scope, element, attrs) {
scope.$watch(attrs.focus, function(newValue, oldValue) {
if(newValue) {
element[0].focus();
}
});
element.bind("blur", function(e) {
$timeout(function() {
scope.$apply(attrs.focus + "=false");
}, 0);
});
element.bind("focus", function(e) {
$timeout(function() {
scope.$apply(attrs.focus + "=true");
}, 0);
})
}
}
})
And then you can use it in the input.
<input type="text" ng-init="inp_focus = true" focus="inp_focus" />
Please check this example.
http://jsfiddle.net/Serhioromano/bu2k2cb7/

Resources