Im trying to call the validation function from directive in the controller. Is it possible?
My directive is something like this:
app.directive('evenNumber', function(){
return{
require:'ngModel',
link: function(scope, elem, attrs, ctrl){
ctrl.$parsers.unshift(checkForEven);
function checkForEven(viewValue){
if (parseInt(viewValue)%2 === 0) {
ctrl.$setValidity('evenNumber',true);
}
else{
ctrl.$setValidity('evenNumber', false);
}
return viewValue;
}
}
};
});
I want to call the function checkForEven from the controller.
$scope.copyFileContentToEditor = function(){
$scope.code = $scope.content;
// TODO call the checkForEven directive function to validate the $scope.code
}
Is it possible to do that? Any suggestions?
You may need to define a link between your controller and your directive to get them know each other.
app.controller('MainCtrl', function($scope) {
$scope.name = 'World'; // this is just used for your directive model, it is not the part of the answer
$scope.vm = {} // define this to create a shared variable to link the controller and directive together.
});
app.directive('evenNumber', function(){
return{
require:'ngModel',
scope: {'vm': '='},
restrict: 'A',
link: function(scope, elem, attrs, ctrl){
function checkForEven(){
alert('I get called.')
}
scope.vm.checkForEven = checkForEven; // once the directive's method is assigned back to "vm", so you could trigger this function from your controller by call this vm.checkForEven;
}}})
HTML
<div ng-model="name" even-number vm="vm"></div>
Plunker Example
Add the function as a property of the ngModel controller:
app.directive('evenNumber', function(){
return{
require:'ngModel',
link: function(scope, elem, attrs, ctrl){
ctrl.$parsers.unshift(checkForEven);
//ADD checkForEven to ngModel controller
ctrl.checkForEven = checkForEven;
function checkForEven(viewValue){
if (parseInt(viewValue)%2 === 0) {
ctrl.$setValidity('evenNumber',true);
}
else{
ctrl.$setValidity('evenNumber', false);
}
return viewValue;
}
}
};
});
Then name the form and input element:
<form name="form1">
<input name="input1" ng-model="vm.input1" even-number />
</form>
The controller can then reference it where it attaches to scope:
$scope.copyFileContentToEditor = function(){
$scope.code = $scope.content;
//CALL the function
$scope.form1.input1.checkForEven($scope.vm.input1);
}
Related
I want one of the Radio Button to be selected once the page is loaded, from another question on stackoverflow i found that Radio Button will be check if the value of the input attribute is equal to the value of model applied on the Radio Button. But i am unable to access the model($parent.selectedItem) on Radio Button in link function inside child directive. Api i used in example is a placeholder but in realtime i will have a property selected which will be true/false which I want to bind to the $parent.selectedItem
var mainApp = angular.module('mainApp', []);
mainApp.factory('myFactory', function ($http) {
var myFactory = {
myMethod: function () {
var promise = $http.get('https://jsonplaceholder.typicode.com/users').then(function (response) {
return response.data;
});
return promise;
}
};
return myFactory;
});
Controller:
mainApp.controller('myController', function ($scope, myFactory) {
myFactory.myMethod().then(function (result) {
$scope.data = result
})
});
Directives:
mainApp.directive('parent', function (myFactory) {
return {
restrict: 'E',
replace: true,
scope: true,
templateUrl: 'parent.html',
link: function (scope, element, attrs, ctrl) {
myFactory.myMethod().then(function (result) {
scope.Model = result
})
}
}
});
mainApp.directive('child', function () {
return {
restrict: 'E',
scope: {
Model: '=ngModel'
},
replace: true,
require: 'ngModel',
templateUrl: 'child.html',
link: function (scope, element, attrs, ctrl) {
// unable to access scope.selectedItem
console.log(scope.selectedItem)
}
}
});
HTML:
// mainpage.html
<body ng-app="mainApp"><parent></parent></body>
//parent.html
<div><child ng-model = "Model"></child></div>
//child.html
<div ng-repeat="item in Model"><input type="radio" name="itemSelected"
ng-value="item" ng-model="$parent.selectedItem"/>{{item.name}}</div>
when you require ngModel in the child directive, what you're basically requiring is its controller, this controller is then injected into your link function as the 4th parameter, in your case the ctrl argument.
so right now your ngModel might work, but it is not in your link function because you're expecting it to exist on the scope as selectedItem, but on your scope you have declared it as Model (not selectedItem). However, you also have access to the ngModel controller, so you could ask for its value there through its controller: https://docs.angularjs.org/api/ng/type/ngModel.NgModelController.
ex:
ctrl.$viewValue
// or
ctrl.$modelValue
//whichever serves your purpose
I am trying to do some custom validation based on a json object a user gives me.
However the input field visually does not show the value of the ngModel property. I added a plunkr to illustrate the problem.
'use strict';
angular.module('zendantennesApp')
.directive('validation', function ($compile, $parse) {
return {
scope: {
validation: '#',
ngModel: '#'
},
require: "?ngModel",
restrict: 'A',
compile: function(el, attrs) {
el.removeAttr('validation');
el.attr('ng-blur', 'evaluateExpression()');
el.attr('ng-focus', 'assignOriginalValue()');
var fn = $compile(el);
return function(scope, element, attrs, ngModel){
ngModel.$render = function(){
$(element).val(ngModel.$viewValue);
};
fn(scope);
}
},
controller: function($scope){
$scope.originalValue = $scope.ngModel;
$scope.validationObject = JSON.parse($scope.validation.replace(/'/g, '"'));
$scope.evaluateExpression = function(){
console.log($scope.validationObject);
};
$scope.assignOriginalValue = function(){
$scope.originalValue = $scope.ngModel;
console.log($scope.originalValue);
}
}
}
});
https://plnkr.co/edit/1qYxCiSZWHgVeN9CEpxw?p=preview
validation directive will have isolated scope and hence parent scope value will not be accessible unless you explicitly mention during compile. Replace fn(scope); by fn(scope.$parent);
Updated Plunker
I'm using a jQuery-ui datapicker and have defined a directive (credit: http://www.abequar.net/posts/jquery-ui-datepicker-with-angularjs) to instantiate it. I'd now like to add an html attribute that defines the function to call to determine whether a day should be selectable in the datepicker. How would I do this?
The js:
//Directive for showing the jquery-ui datepicker
myApp.directive('datepicker', function() {
return {
restrict: 'A',
require : 'ngModel',
link : function (scope, element, attrs, ngModelCtrl) {
$j(function(){
//Instantiate the datepicker
element.datepicker({
dateFormat:'dd/mm/yy',
beforeShowDay:function(date) {
//TODO Call function defined in attrs, passing the date object to it
theDefinedFunction(date)
},
onSelect:function (date) {
ngModelCtrl.$setViewValue(date);
scope.$apply();
}
});
});
}
}
});
The html:
<input type="text" datepicker show-days="myShowDaysFunction()" />
The myShowDaysFunction() would be defined in the controller.
(Edit) - Controller function:
$scope.myShowDaysFunction = function(date) {
console.log("I get called"); //Logs to the console
console.log(date); //Logs undefined to the console
}
Thanks.
You need to create an isolate scope on your directive and take the function as a scope variable.
myApp.directive('datepicker', function() {
return {
restrict: 'A',
require : 'ngModel',
scope: {
showDays: '&'
},
link : function (scope, element, attrs, ngModelCtrl) {
$j(function(){
//Instantiate the datepicker
element.datepicker({
dateFormat:'dd/mm/yy',
beforeShowDay:function(date) {
//TODO Call function defined in attrs, passing the date object to it
scope.showDays({date: date});
},
onSelect:function (date) {
ngModelCtrl.$setViewValue(date);
scope.$apply();
}
});
});
}
}
});
Markup
<input type="text" datepicker show-days="myShowDaysFunction(date)" />
Controller Function
$scope.myShowDaysFunction = function(date) {
alert(date);
}
Plunker Exmaple
http://plnkr.co/edit/kRc76icPUa9qTkPH4UKm?p=preview
I am using ng-repeat and setting a model with it similar to the following
<div ng-repeat="thing in things" ng-model="thing" my-directive>
{{thing.name}}
</div>
then in my directive it looks something like this
.directive("myDirective, function () {
return {
require: 'ngModel',
link: function(scope, lElement, attrs, model) {
console.log(model.name);// this gives me 'NAN'
}
}
})
My question is how can I access the values in the model? I tried model.$modelValue.name but that did not work.
If you want to bind in a scoped value then you can use the '=' in an isolated. This will appear on the scope of your directive. To read the ng-model directive, you can use =ngModel:
.directive("myDirective", function () {
return {
scope: {
model: '=ngModel'
}
link: function(scope) {
console.log(scope.model.name); // will log "thing"
}
}
});
.directive("myDirective", function () {
return {
require: 'ngModel',
link: function(scope, lElement, attrs, model) {
console.log(attrs.ngModel); // will log "thing"
}
}
})
If your directive does not have isolated or child scope then you can do this:
.directive('someDirective', function() {
return {
require: ['^ngModel'],
link: function(scope, element, attrs, ctrls) {
var ngModelCtrl = ctrls[0];
var someVal;
// you have to implement $render method before you can get $viewValue
ngModelCtrl.$render = function() {
someVal = ngModelCtrl.$viewValue;
};
// and to change ngModel use $setViewValue
// if doing it in event handler then scope needs to be applied
element.on('click', function() {
var val = 'something';
scope.$apply(function() {
ngModelCtrl.$setViewValue(val);
});
});
}
}
});
Not sure how to phrase the question so please edit if you can come up with something better. I have the following directive:
app.directive('foo', function() {
return {
restrict: 'A',
require: "?ngModel",
link: function (scope, element, attrs, controller) {
scope.$watch(attrs.ngModel, function () {
console.log("Changed to " + scope[attrs.ngModel]);
});
}
};
});
When I have this it works great and logs properly
<input type="text" ng-model="bar" />
app.controller('fooController', function($scope) {
$scope.bar = 'ice cream';
});
It doesn't work when I try it this way around. It keeps logging 'Changed to undefined'
<input type="text" ng-model="model.bar" />
app.controller('fooController', function($scope) {
$scope.model = { bar: 'ice cream' };
});
How do I make it work for both scenarios. It seems the right thing to do seeing as angular lets you use both.
I looked at ngModel directive and found a function called ngModelGet. Uses $parse.
app.directive('foo', function($parse) {
return {
restrict: 'A',
require: "?ngModel",
link: function (scope, element, attrs, controller) {
var ngModelGet = $parse(attrs.ngModel);
scope.$watch(attrs.ngModel, function () {
console.log("Changed to " + ngModelGet(scope));
});
}
};
});
your can use
var ngModelCtrl = controller;
ngModelCtrl.$viewValue
replace
scope[attrs.ngModel]
here is ngModelCtrl sdk