Custom Directive, requires some condition before kick-in the required field - angularjs

I'm new to AngularJS and still learning.
I'm trying to create a custom directive and I would like to have some conditions where requires some conditions before the customrequired kick-in. For example checkbox is ticked. Below is my sample directive and HTML. Thanks and really appreciate your response. Please let me know if you still need some information.
.directive('customrequired', function () {
return {
require: '?ngModel',
link: function (scope, elm, attr, ctrl) {
if (!ctrl) return;
//conditional approach like, requires checkbox to be checked.?
}
};
})
HTML
<input type="text" ng-model="Create.ProductName" name="ProductName" customrequired="Create.IsRequired == 1"/>
<input type="checbox" ng-model="Create.IsRequired" name="Required" />

You can do put watch on your directive value and put your logic in only if its true.
.directive('customrequired', function () {
return {
require: '?ngModel',
link: function (scope, elm, attr, ctrl) {
scope.$watch(attr.customrequired,function(value){
if(value){
//conditional approach like, requires checkbox to be checked.?
}
})
}
};
})

Related

Proper way to validate an input is numeric in angular

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>

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

Password Confirmation Validation when origin changes

So, I need a validator that will check to make sure my password_confirmation field matches my password field. I ended up with the following directive:
Directive
#app.directive 'matches', ->
require: 'ngModel', #Needed for validation bits
scope: { matched_value: '=matches' } #Looks up the value of the scope element we're matching against and keeps it bound
link: (scope, elem, attrs, ctrl) ->
ctrl.$parsers.unshift (view_value) -> #Add a new parser that updates the validity
ctrl.$setValidity(elem.attr('name'), view_value == scope.matched_value)
Form
<form name="form">
<input ng-model="new_user.password" name="password">
<input ng-model="password_confirmation" name="password_confirmation" matches="new_user.password">
</form>
This works fine when the user uses the form from top to bottom. However, if they go on to change the password after they've filled in the password_confirmation then it doesn't become invalid like it should.
My first stab looked added a $watcher to the matches directive, but I can't seem to get the correct value of the new password_confirmation input.
Directive w/ Watcher (CoffeeScript)
#app.directive 'matches', ->
require: 'ngModel',
scope: { matched_value: '=matches' }
link: (scope, elem, attrs, ctrl) ->
ctrl.$parsers.unshift (view_value) ->
ctrl.$setValidity(elem.attr('name'), view_value == scope.matched_value)
scope.$watch attrs['watches'], ->
ctrl.$setValidity(elem.attr('name'), ctrl.$view_value == scope.matched_value)
But ctrl.$view_value is always undefined, leading me to believe that I'm doing this wrong.
How would I get the actual value? Is this the correct way to set up this sort of inverse relationship? Is there a better way to do this?
https://github.com/wongatech/angular-confirm-field is a good project for this.
Example here http://wongatech.github.io/angular-confirm-field/
The code below shows 2 input fields with the implemented functionality
<input ng-model="email" name="my-email" />
<input ng-confirm-field ng-model="emailconfirm" confirm-against="email" name="my-email-confirm"/>
This directive differs from other implementations in the way it uses $parsers and $watch to ensure the model property is only updated when the view value is valid.
You can watch both elements from the one directive. Pass a function to watch. Each digest, it will compare values instead of only when the one element changes.
.directive('match', function () {
return {
require: 'ngModel',
restrict: 'A',
scope: {
match: '='
},
link: function(scope, elem, attrs, ctrl) {
scope.$watch(function() {
var modelValue = ctrl.$modelValue || ctrl.$$invalidModelValue;
return (ctrl.$pristine && angular.isUndefined(modelValue)) || scope.match === modelValue;
}, function(currentValue) {
ctrl.$setValidity('match', currentValue);
});
}
};
});
With (ctrl.$pristine && angular.isUndefined(ctrl.$modelValue)), it will not add the error until the field is touched or something is in it (pre-filled).
More info: https://github.com/TheSharpieOne/angular-input-match
Demo: http://jsfiddle.net/TheSharpieOne/Wnv8u/
For version 1.3.x of angular, the new validation pipeline works best, here is the version for angular 1.3.x
.directive('match', function () {
return {
require: 'ngModel',
restrict: 'A',
scope: {
match: '='
},
link: function(scope, elem, attrs, ctrl) {
scope.$watch('match', function(pass){
ctrl.$validate();
});
ctrl.$validators.match = function(modelValue){
return (ctrl.$pristine && (angular.isUndefined(modelValue) || modelValue === "")) || modelValue === scope.match;
};
}
};
});

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