I am new to angular js and want to validate a field on blur.
As i am entering the value the directive is called and is validating the entered value. i want this to happen on -blur.
I have already user on-blur in the html for calling some other function.
Below is the directive :
app.directive("emailCheck", function(){
return {
require: 'ngModel',
link: function (scope, elm, attrs, ctrl) {
ctrl.$parsers.unshift(function (viewValue, $scope) {
var emailPattern = /\S+#\S+\.\S+/;
var isEmailValid = emailPattern .test(viewValue)
ctrl.$setValidity('emailFormat', isEmailValid);
return viewValue;
})
}
};
});
How do i check for on blur event here?
Thanks in advance.
you should bind blur event to directive. try like this:
link: function (scope, elm, attrs, ctrl) {
elm.bind('blur',function(){
})
}
var app = angular
.module('MyApp', [
])
.controller('Main', ['$scope', function ($scope) {
}])
.directive("emailCheck", function(){
return {
require: 'ngModel',
link: function (scope, elm, attrs, ctrl) {
elm.bind('blur',function(){
alert("test");
})
}
};
});
<script src="https://ajax.googleapis.com/ajax/libs/angularjs/1.2.23/angular.min.js"></script>
<div class="main-content" ng-app="MyApp" ng-controller="Main as myCtrl">
<div>
<input type="text" ng-model="email" email-check>
</div>
</div>
Conventionally, when you use ngModel in your directive, you do not decide what event to hook into. You subscribe to whatever event the ngModel is hooked up to. This is not just blur by default.
The user of your directive can use ngModelOptions with updateOn:blur`` to update only on blur, like:
<input
email-check
name="testEmail" ng-model="testEmail"
ng-model-options="{ updateOn: 'blur' }">
<!-- Note using "updateOn: 'blur'" NOT "updateOn: 'default blur'" -->
ngModelOptions Docs
You will have to handle blur event inside the directive and remove the same from html element to handle it in the below fashion:
app.directive("emailCheck", function(){
return {
require: 'ngModel',
link: function (scope, elm, attrs, ctrl) {
elm.on('blur', function() {
// #TODO you will have to put your code here to handle this event
});
}
};
});
Try this.
define(['app'],function(app){
app.directive('myDecimals', function() {
return {
restrict: 'A',
link: function(scope, elm, attrs) {
elm.bind('blur',function(){
elm.val(elm.val()*1);
});
}
};
});
});
Related
I have a controller:
function myController($scope) {
$scope.clicked = false;
}
and a directive:
function myDirective() {
return {
restrict: 'E',
link: function(scope, elem, attrs) {
elem.bind('click', function() {
// need to update controller $scope.clicked value
});
},
template: '<div>click me</div>';
replace: true;
}
}
and I´m using it like this:
<div ng-controller="myController">
<my-directive></my-directive>
</div>
How can I change the controller value of $scope.clicked ?
thanks!
As you don't use isolated scope in your directive, you can use scope.$parent.clicked to access the parent scope property.
link: function(scope, elem, attrs) {
elem.bind('click', function() {
scope.$parent.clicked = ...
});
},
I would not recommend using scope.$parent to update or access the parent scope values, you can two way bind the controller variable that needs to be updated into your directive, so your directive becomes:
function myDirective() {
return {
restrict: 'E',
scope: {
clicked: '='
},
link: function(scope, elem, attrs) {
elem.bind('click', function() {
// need to update controller $scope.clicked value
$scope.clicked = !$scope.clicked;
});
},
template: '<div>click me</div>';
replace: true;
}
}
now pass this clicked from parent:
<div ng-controller="myController as parentVm">
<my-directive clicked="parentVm.clicked"></my-directive>
</div>
function myController() {
var parentVm = this;
parentVm.clicked = false;
}
I would recommend reading up on using controllerAs syntax for your controller as that would really solidify the concept of using two way binding here.
I like to use $scope.$emit for such purposes. It allows to send data from directive to the controller.
You should create custom listener in your controller:
$scope.$on('cliked-from-directive', function(event, data){
console.log(data)
})
As you can see, now you have full access to your controller scope and you can do whatever you want. And in your directive just to use scope.$emit
link: function(scope, elem, attrs) {
elem.bind('click', function() {
scope.$emit('cliked-from-directive', {a:10})
});
Here I've created jsfiddle for you
I'm using angular 1.4.x.
I'm making a custom directive that checks weather a field is unique on the server (the field is called "jmbg"). I have the following code:
(function() {
angular
.module('app')
.directive('uniqueJmbg', uniqueJmbg);
uniqueJmbg.$inject = ['$q', '$http'];
function uniqueJmbg($q, $http) {
restrict: 'A',
require: 'ngModel',
link: function(scope, elem, attrs, ngModelCtrl) {
ngModelCtrl.$asyncValidators.uniqueJmbg = function(modelValue, viewValue) {
var value = modelValue || viewValue;
return $http.get('/server/users/' + value)
.then(function resolved() {
return $q.reject('exists');
}, function rejected() {
return true;
});
};
}
}
})();
I am using the directive in HTML in the following way:
<input class="form-control" type="text" id="jmbg" name="jmbg" ng-model="rad.radnik.jmbg" ng-model-options="{ updateOn: 'default blur', debounce: {'default':400, 'blur':0 } }" unique-jmbg/>
In case it matters, I'm using my controllers with the controllerAs syntax.
Now, what happens is that the file containing my uniqueJmbg definition never loads (I can't see it in the browser debugger). If I move my code to a component which does load the app stops working (and there are no errors in the console), so there is no way for me to debug this.
Any idea what might be so wrong I can't even access the code in the browser?
Add dependencies to the module
angular
.module('app', [])
.directive(...
And you need to return an object from the module, so the correction would be:
function uniqueJmbg($q, $http) {
return {
restrict: 'A',
require: 'ngModel',
link: function(scope, elem, attrs, ngModelCtrl) {
...
}
};
}
I have the following code:
<div id='parent'>
<div id='child1'>
<my-select></my-select>
</div>
<div id='child2'>
<my-input></my-input>
</div>
</div>
I also have two directives which get some data from the data factory. I need the two directives to talk to each other such that when a value in select box is changed the input in changes accordingly.
Here's my two directives:
.directive("mySelect", function ($compile) {
return {
restrict: 'E',
scope:'=',
template: " <select id='mapselectdropdown'>\
<option value=map1>map1</option> \
<option value=map2>map2</option> \
</select>'",
link: function (scope, element, attrs) {
scope.selectValue = //dont konw how to get the value of the select
}
};
})
.directive("myInput", function($compile) {
return {
restrict: 'E',
controller: ['$scope', 'dataService', function ($scope, dataService) {
dataService.getLocalData().then(function (data) {
$scope.masterData = data.input;
});
}],
template: "<input id='someInput'></input>",
link: function (scope, element, attrs) {
//here I need to get the select value and assign it to the input
}
};
})
This would essentially do the onchange() function that you can add on selects. any ideas?
You could use $rootScope to broadcast a message that the other controller listens for:
// Broadcast with
$rootScope.$broadcast('inputChange', 'new value');
// Subscribe with
$rootScope.$on('inputChange', function(newValue) { /* do something */ });
Read Angular docs here
Maybe transclude the directives to get access to properties of outer scope where you define the shared variable ?
What does this transclude option do, exactly? transclude makes the contents of a directive with this option have access to the scope outside of the directive rather than inside.
-> https://docs.angularjs.org/guide/directive
After much research this is what worked...
I added the following:
.directive('onChange', function() {
return {
restrict: 'A',
scope:{'onChange':'=' },
link: function(scope, elm, attrs) {
scope.$watch('onChange', function(nVal) { elm.val(nVal); });
elm.bind('blur', function() {
var currentValue = elm.val();
if( scope.onChange !== currentValue ) {
scope.$apply(function() {
scope.onChange = currentValue;
});
}
});
}
};
})
Then on the element's link function I added:
link: function (scope, elm, attrs) {
scope.$watch('onChange', function (nVal) {
elm.val(nVal);
});
}
Last added the attribute that the values would get set to in the scope:
<select name="map-select2" on-change="mapId" >
So I know that I can have the model be different than the view value by using $parsers.
But what if I want to have the model change, without using $parsers?
For example:
html
<input tel-input ng-model="data.phone">
{{data.phone}}
js
.directive('telInput', function($compile) {
return {
restrict: 'A',
scope: {
ngModel: '='
},
link: function(scope, elem, attrs) {
elem.on('paste', function() {
scope.ngModel = 'special model value after pasting';
});
}
};
});
The problem with this is that when scope.ngModel = 'pasting not allowed occurs, it changes the value in the input.
With $parsers, it changes the value in the model, but the view value remains the same.
There isn't any $setModelValue method, which seems like it would serve this purpose.
Any ideas?
Try this,
.directive('telInput', function() {
return {
restrict: 'A',
require: 'ngModel',
link: function(scope, elem, attrs, ngModel) {
elem.on('paste', function() {
ngModel.$setViewValue('special model value after pasting');
ngModel.$render();
});
}
};
});
With HTML like this...
<div ng-app="myApp">
<div ng-controller="inControl">
I like to drink {{drink}}<br>
<input my-dir ng-model="drink"></input>
</div>
</div>
and javascript like this...
var app = angular.module('myApp', []);
app.controller('inControl', function($scope) {
$scope.drink = 'water';
});
app.directive('myDir', function(){
return {
restrict: 'A',
link: function($scope, element, attrs, ctrl) {
// why is this logging undefined?
console.log(ctrl);
}
};
});
Why can I not access the controller from within my directive? Why is my call to ctrl giving me undefined?
EDIT: add demo...
Fiddle available here: http://jsfiddle.net/billymoon/VE9dX/
see multiple controller can be attached with one app and simillarly multiple directive can be attached with one app, so if you wants to use one controller in one directive than you can set the controller property of directive to the name of the controller you wants yo attach with like in your case
app.directive('myDir', function(){
return {
restrict: 'A',
controller: 'inControl'
link: function($scope, element, attrs, ctrl) {
// why is this logging undefined?
console.log(ctrl);
}
};
});
Despite this working with require:ngModel, this still isn't the best approach as it ties the directive directly to the controller. If you want your directive to communicate with your controller, you could be setting and reading off the scope.
HTML:
<div ng-app="myApp">
<div ng-controller="inControl">
I like to drink {{drink}}<br />
<input my-dir="drink"></input>
</div>
</div>
JS:
var app = angular.module('myApp', []);
app.controller('inControl', function($scope) {
$scope.drink = 'asdfasdf';
});
app.directive('myDir', function(){
return {
restrict: 'A',
link: function(scope, element, attrs) {
console.log(scope[attrs.myDir]);
}
};
});
Alternatively you can use my-dir="{{drink}}" and read it as attrs.myDir.
http://jsfiddle.net/8UL6N/1/
Adding require: 'ngModel', fixed it for me - not sure if there is another way to specify it...
app.directive('myDir', function(){
return {
restrict: 'A',
require: 'ngModel',
link: function($scope, element, attrs, ctrl) {
// why is this logging undefined?
console.log(ctrl);
}
};
});