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);
}
};
});
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'm having trouble with an angular directive. It doesn't seem to run the link function.
I feel like it's something obvious, but I just can't figure it out.
The directive is required as seen from below
angular.module('test').requires // ["injectedModule"]
Code below. Fiddle.
Any help would be amazing.
angular
.module('test', ['injectedModule'])
.controller('tester', [
function() {
this.test = function(data) {
alert(data);
}
}
]);
angular
.module('injectedModule', [])
.directive('testing', [
function() {
return {
restrict: 'E',
scope: true,
link: function(scope, element, attrs) {
alert(scope, element, attrs);
}
};
}
]);
<div ng-app="test">
<div ng-controller="tester as t">
<video id="test" ng-src="https://scontent.cdninstagram.com/hphotos-xfa1/t50.2886-16/11726387_1613973172221601_1804343601_n.mp4" testing="t.test(el)" />
</div>
</div>
Looks to me like
restrict: 'E',
should be
restrict: 'A',
Your directive isn't being called at all as it is.
I think the error is in the restriction you are giving to your directive.
You are restricting your directive to match only element (in other words tag). You should restrict to match attribute 'A'. Here's angular official documentation https://docs.angularjs.org/guide/directive
and here's your fiddle working
Code sample:
angular
.module('injectedModule', [])
.directive('testing', [
function() {
return {
restrict: 'A',
scope: true,
link: function(scope, element, attrs) {
alert(scope, element, attrs);
}
};
}
]);
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" >
I am trying to implement dynamically configurable fields. I will get validation rules ng-required, ng-hidden, ng-disabled etc attributes as json from the server and set them dynamically through a directive.
I have the following directive code. It displays select values doubled JsBin link is http://jsbin.com/jiququtibo/1/edit
var app = angular.module('myapp', []);
app.directive('inputConfig', function( $compile) {
return {
require: 'ngModel',
restrict: 'A',
scope: '=',
compile: function(tElem, tAttrs){
console.log("compile 2");
tElem.removeAttr('data-input-config');
tElem.removeAttr('input-config');
tElem.attr('ng-required',true);
return {
pre: function (scope, iElement, iAttrs){
console.log('pre');
},
post: function(scope, iElement, iAttrs){
console.log("post");
$compile(tElem)(scope);
}
}
}
};
});
How can I solve this issue? I should be able to add directive dynamically.
To solve your problem you need to remove the following line from your post function:
$compile(tElem)(scope);
It's not clear to me why you are compiling here so I'm not sure if there will be any unintended side effects from this.
I found a solution following code is working.You should first clone, remove directive, prepare dom and compile
app.directive('inputConfig', function( $compile) {
return {
require: '?ngModel',
restrict: 'A',
compile:function (t, tAttrs, transclude){
var tElement = t.clone() ;
tElement.removeAttr('input-config');
tElement.attr('ng-required',true);
t.attr('ng-required',true);
return function(scope){
// first prepare dom
t.replaceWith(tElement);
// than compile
$compile(tElement)(scope);
};
}
}
});