Proper way to validate an input is numeric in angular - angularjs

I have the following directive in angular:
define(function(require) {
var angular = require('angular');
angular.module('is-numeric', [])
.directive('isNumeric', [function() {
return {
require: 'ngModel',
restrict: 'A',
link: function(scope, elem, attrs, ctrl) {
elem.on('keyup', function(e) {
ctrl.$setValidity('isnumeric', !isNaN(e.target.value));
});
}
};
}]);
});
Do I really need to add an event handler for the keyup or is there a better way?

you should use validators:
link: function(scope, elem, attrs, ctrl) {
ctrl.$validators.isnumeric = function(modelValue, viewValue){
return !isNaN(viewValue);
};
}

For this you should not use any directives.
My suggestion is that use the built in ng-pattern validator, which will handle the case you described.
You can check here: https://docs.angularjs.org/api/ng/directive/ngPattern
<input ng-model="validatedNumber" ng-pattern=$scope.numberValidation/>
and in you controller you should define the regular expression like this:
$scope.numberValidation = /^(0|[1-9][0-9]*)$/;
Edit: what I forgot in my explanation is that, you should put this into a form, then when you would like to validate/send the form you should check the form validity like this:
if(formname.$valid())
where formname is the name of the DOM element which is defined as a form
<form name="formname"> [...] </form>

Related

How to add a button to an input field using AngularJS directive?

I need to write a directive that can would add a button to an input field and some other functionality.
So, ideally I want to have something like this
<input type="text" my-directive>
to end up being
<input type="text"><button ng-click="someAction()" ng-class="{'success': isSuccess()}" ng-disabled="isDisabled()">click me</button>
Simplified code for my directive:
app.directive('myDirective', ['$q', '$timeout', function ($q, $timeout) {
return {
restrict: 'A',
template: '<button ng-click="someAction()" ng-class="{\'success\': isSuccess()}" ng-disabled="isDisabled()">click me</button>',
require: '?ngModel',
link: function (scope, element, attrs, ctrl) {
scope.isSuccess = function () {
...
};
scope.isPending = function () {
...
};
scope.someAction = function () {
...
};
....}]);
The problem is that if I add this button in directive's template I end up with <input><button></button></input>
Creating a directive that would include also an input field is unfortunately not an option for me.
Please let me know if I need to provide more info.
After some searching, I have found a solution.
You can add a the element by compiling it in your directive's link function and appending it to the element.
link: function (scope, element, attrs, ctrl) {
var tpl = <button ng-click="someAction()" ng-class="{\'success\': isSuccess()}" ng-disabled="isDisabled()">click me</button>';
var el = $compile(tpl)(scope);
element.after(el);
...}

Angular Directive would not update ng-model

I can't seem to find a way to update my ng-model in my directive
My directive looks like this
app.directive('DatepickerChanger', function () {
return {
restrict: 'E',
require: 'ngModel',
scope: {
Model: '=',
startDate: '=',
endDate: '=',
},
templateUrl: function(elem,attrs) {
return '/AngularJS/Directives/msDatepickerTpl.html'
},
link: function (scope, element, attrs, ngModel) {
ngModel = new Date();
}
}
});
And i use it like this
<DatepickerChanger ng-model="date" required></DatepickerChanger>
Where date is a other date object
If i console.log the ng-model, i can see that it's change it's value, but can't see it from the place where i call the directive. anyone got a clue to what im doing worng
You are using it wrong. This ngModel is a controller. Your code should look like this:
link: function (scope, element, attrs, ngModel) {
ngModel.$setViewValue(new Date());
}
Also, the directive should be called datepickerChanger and referenced in html as datepicker-changer
EDIT:
You want to update the ngModel after changing the input, for example. One way to do that is use the bind function to capture the events of the input field (I cant see your template, but I imagine that will have one input):
link: function (scope, element, attrs, ngModel) {
element.find('input').bind('change', function() {
// Do something with this.value
ngModel.$setViewValue(newDate);
});
}

How do I conditionally apply a custom validator to a form field?

I have a re-usable directive where the use of a custom validator is optional.
What's a good way to apply this validator attribute conditionally?
<input type="text"
name="{{name}}"
require-items="{{requireitems}}"
mongoose-error>
The require-items is an optional validation I want to pass to my directive.
The directive would be called like this:
//with validator enabled
<my-directive requireitems="{{items.length}}"></my-directive>
//no validator
<my-directive></my-directive>
Inside your my-directive directive link function:
link: function(scope, iElement, iAttrs, controller) {
if(iAttrs.requireItems) {
// checks if require-items is present
// process your validation here
}
}
Check how it's done in ng-required, using attributes and observing the same to have dynamic changes also handled.
var requiredDirective = function() {
return {
restrict: 'A',
require: '?ngModel',
link: function(scope, elm, attr, ctrl) {
if (!ctrl) return;
attr.required = true; // force truthy in case we are on non input element
ctrl.$validators.required = function(modelValue, viewValue) {
return !attr.required || !ctrl.$isEmpty(viewValue);
};
attr.$observe('required', function() {
ctrl.$validate();
});
}
};
};
GitHub Link

ngModelController $modelValue is empty on directive startup

I have an attribute directive that I use on an input=text tag like this:
<input type="text" ng-model="helo" my-directive />
On my directive I'm trying to use the ngModelController to save the initial value of my input, in this case the value of the ng-model associated with it.
The directive is like this:
app.directive('myDirective', function () {
return {
restrict: "A",
scope: {
},
require: "ngModel",
link: function (scope, elm, attr, ngModel) {
console.log("hi");
console.log(ngModel.$modelValue);
console.log(ngModel.$viewValue);
console.log(elm.val());
}
}
});
The problem is that ngModel.$modelValue is empty maybe because at the time the directive is initialized the ngModel wasn't yet updated with the correct value. So, how can I store on my directive the first value that is set on my input field?
How to correctly access ngModel.$modelValue so that it has the correct value?
I'll also appreciate an explanation on why this isn't working as I'm not clearly understanding this from reading the docs.
Plunkr full example: http://plnkr.co/edit/QgRieF
Use $watch in myDirective
app.directive('myDirective', function () {
return {
restrict: "A",
scope: {
},
require: "ngModel",
link: function (scope, elm, attr, ngModel) {
var unwatch = scope.$watch(function(){
return ngModel.$viewValue;
}, function(value){
if(value){
console.log("hi");
console.log(ngModel.$modelValue);
console.log(ngModel.$viewValue);
console.log(elm.val());
unwatch();
}
});
}
}
});
For Demo See This Link

Angularjs get form field validity inside directive

I'm hoping this isn't a duplicate - plenty of similar questions about but I can't find an answer that works.
I have an Angular directive, thus:
app.directive('emailInput', function(){
return {
restrict: 'E',
templateUrl: 'template.html',
link: function(scope, elem, attrs, ctrl){
elem.bind('keyup', function(){
// TODO - what?
})
}
}
}
and in the template html:
<input type="email" required ng-model="emailAddress" />
Without knowing the name of the form, inside the link function, I want to know the value of the emailAddress.$valid property - how can I get this?
You can require the formController which would give you access to all of the inputs registered to the form
app.directive('emailInput', function(){
return {
require: '^form', // We look for it on a parent, since it will be defined somewhere higher on the DOM.
restrict: 'E',
templateUrl: 'template.html',
link: function(scope, elem, attrs, ctrl){
elem.bind('keyup', function(){
ctrl.emailAddress.$valid //check validity
})
}
}
}
Remember that Angular keeps track of input elements by name. So you have to give your input a name attribute
<input type="email" required ng-model="emailAddress" name="emailAddress" />
I would also recommend possibly just passing all of this through a directive attribute. You probably don't want to hard code the field names. So you could just have an attribute that takes the validity
inputIsValid='formName.emailAddress.$valid'
And evaluate (or $watch it) in your directive.
We can check validity more easily without knowing the name of input elements.
app.directive('emailInput', function(){
return {
require: '^form', // We look for it on a parent, since it will be defined somewhere higher on the DOM.
restrict: 'E',
templateUrl: 'template.html',
link: function(scope, elem, attrs, ctrl){
elem.bind('keyup', function(){
ctrl.$valid //check validity here
})
}
}
}
This is an old post but for the people who get here by googling, this is the cleanest way to check validity of an input in your directive without knowing its name, so you can use your directive on any input element.
You just need to require the ngModelcontroller:
app.directive('emailInput', function(){
return {
require: 'ngModel'
restrict: 'E',
templateUrl: 'template.html',
link: function(scope, elem, attrs, ngModelCtrl){
elem.bind('keyup', function(){
ngModelCtrl.$valid //check validity
})
}
}
}
See the AngularJS document for ngModel.NgModelController, $valid under the Properties section:
https://docs.angularjs.org/api/ng/type/ngModel.NgModelController
Know it's an old thread but if someone runs into this problem this is how I solved it:
app.directive('emailInput', function(){
return {
restrict: 'E',
templateUrl: 'template.html',
controller:function($scope){
$scope.isInvalid = function(){
return $scope.myelem.data().$ngModelController.$invalid;
}
},
link: function(scope, elem, attrs){
$scope.myelem = $(elem).find("input");
}
}
}
Here is a directive that will set dirty to true even if nothing has been typed in.
By default $dirty is set if something is typed in and wouldn't show a required error message until the user submits. With this
function() {
return function (scope, element, attrs) {
$(element).blur(function () {
scope.$apply(function() {
var field = scope.$eval(attrs.makeDirty);
field.$dirty = true;
});
});
};
HTML:
<label class="fieldLabel" for="confirmEmail">Confirm Email*</label>
<input type="text" id="confirmEmail" name="confirmEmail" ng-model="confirmEmail" ng-pattern="{{Ctrl.Model.Email.EmailAddress}}" required make-dirty="form.confirmEmail">
<span class="error" ng-show="form.confirmEmail.$error.pattern && form.confirmEmail.$dirty">Emails must match</span>
<span class="error" ng-show="form.confirmEmail.$error.required && (form.$submitted || form.confirmEmail.$dirty)">Confirm your email</span>
That allows me to give feedback as the user is filling out or tabbing on the form.
Let me give you another way to do it, it can be useful in some cases
link: function (scope, element, attrs, formCtrl) {
scope.fileSizeError=false;
scope.$watch(function () {
return formCtrl.fileP.$error.maxSize;
},function(newValue) {
scope.fileSizeError=newValue;
});
}
In my case I was inside a directive that is used to upload a file so I needed to know the state of the var $error.maxSize in the template so I did in that way.

Resources