I'm trying to call the parent scope's function from the directive. But it's not getting fired. Can any one point out what is it that I'm missing ?
Here is my directive code:
.directive('myComp',function(){
return {
restrict:'E',
scope:{
vname:'&'
}
}
});
Here is the view code:
<my-comp vname="updateVal(val)">
<input type="text" ng-model="nm">
<button ng-click="vname({val:nm})">Save</button>
</my-comp>
And here is the controller code with the function:
.controller('View1Ctrl', ['$scope',function($scope) {
$scope.iname = 'roy';
$scope.updateVal = function(val){
alert('hi');
$scope.iname = val;
}
}])
It works fine if it is written under controller.
<div ng-app="app" ng-controller='View1Ctrl'>
<my-comp vname="updateVal(val)">
.....
Related
I am trying to create one directive which has its own controller which contains some methods. I am setting scope:false to ensure that the directive will not create an isolated scope.
Directive Definition is :
angular.controller("myController", function($scope){
var parentCtrl = this;
parentCtrl.otherMethod = function(){
//Method body
}
})
angular.directive('customDirective',function(){
return {
scope : false,
controller: function(){
var ctrl = this;
this.someMethod = function($scope){
console.log("Hello World");
}
}
}
});
usage:
<div ng-controller="myController as myCtrl">
<custom-directive>
<button ng-click="someMethod()">click me</button>
</custom-directive>
</div>
I am unable to access the method someMethod().
I am not even getting it inside any scope when I am trying to find it through batarang.
Can someone help?
I try to call directive method from controller by using $broadcast.
But I catch event only if press on button twice.
See Demo in Plunker
Do I miss something?
Here is snippets of code:
HTML
<div ng-controller="MainCtrl">
<test-dir name="{{test}}"></test-dir>
<select ng-model="broadcastTo" ng-options="x as x for x in ['test1', 'test2', 'test3']"></select>
<button ng-click="broadcastToSelectedChild()">test</button>
</div>
JS
var app = angular.module('angularjs-starter', []);
app.controller('MainCtrl', function($scope) {
// a method that broadcasts to a selected child.
$scope.broadcastToSelectedChild = function (){
$scope.test = $scope.broadcastTo;
console.log('call-' + $scope.test);
$scope.$broadcast('call-' + $scope.test);
};
});
app.directive('testDir', function (){
return {
restrict: 'E',
scope: {
'name': '#'
},
template: '<div>{{name}} called: {{called}}</div>',
link: function(scope, elem, attr) {
scope.called = false;
//set up the name to be used as the listened to event.
var eventOn;
scope.$watch('name', function(v) {
console.log('listen ..','call-' + scope.name);
if(eventOn){
eventOn();
}
eventOn = scope.$on('call-' + scope.name, function (){
alert(scope.name);
});
});
}
};
});
Took example from: HERE
Thanks,
It does not work because you bind your directive scope's name to your controller scope's test, but ng-model on the <select> binds to broadcastTo. When you select a value from the <select>, test is not updated and $watch inside your directive does not fire to attach the event handler.
Try:
<test-dir name="{{broadcastTo}}"></test-dir>
DEMO
In your code, you have to click twice because the first click updates test and causes $watch to fire to attach the event handler:
$scope.test = $scope.broadcastTo;
And the second click will be able to handle the event broadcast from your controller.
I have set up the plunker to demonstrate the issue. The click of Bob button doesn't works. What I expected was, the child elements of the directive element will have the same isolated scope. Do I have to move the child elements into the template property of the directive?
I would define some object pass. Set up pass with method setDirectiveTitle and title:
Demo Plunker
JS
angular.module("myApp", [])
.directive("myScopedDirective", function() {
return {
scope: {
pass: '=',
preffix: "#msdTitle"
},
link: function($scope, $element, $attributes) {
$scope.pass.setDirectiveTitle = function(title) {
$scope.pass.title = $scope.preffix + title;
}
}
};
})
.controller("AppController", ["$scope", function($scope) {
$scope.passVal = {};
$scope.setAppTitle = function(title) {
$scope.passVal.title = title;
};
}]);
HTML
<div ng-controller="AppController">
<h2>{{title}}</h2>
<button ng-click="setAppTitle('App 2.0')">Upgrade Me!</button>
<div my-scoped-directive pass="passVal" msd-title="I'm a directive inside the app: {{passVal.title}}">
<h2>{{passVal.title}}</h2>
<button ng-click="passVal.setDirectiveTitle('Bob')" >Bob It!</button>
</div>
</div>
Problem is that is not compiled, you have to use transclusion in order to compile html inside a directive.
http://plnkr.co/edit/hGKeTqqU62Na0MWPvBIZ?p=preview
Or you can simply pass an template:
http://plnkr.co/edit/ZYhTdlwSDp0L3jjErOQt?p=preview
But you cannot use scope attribute binding in this case. Because on second update of parent scope , third click on child will not be updated as you expected.
You have to propagate data differently.
I have created one directive in Angularjs in which I need to use callBackMethod, so that I can call Controller's Function.
Controller's function is called.But Controller's Function is returning some value.I want to get that value in callback function.How to achieve that?
Below is my code for Directive
.directive('abcOption', function($compile) {
return {
restrict : 'A',
template : '<div class="filter-content"></div>',
replace : true,
scope : {
callBackMethod:'&getDisplayName'
},link: function(scope,element,attrs)
{
scope.getDataName =function(dataId)
{
scope.callBackMethod(dataId);
};
}
};
});
Below Code is for Controller function
$scope.getDisplayName = function(columnName) {
return 'abc';
};
It's small snippet of the code. Controller function is called but I am not getting return value in directive function. I am getting undefined in console log if I log scope.callBackMethod(dataId);
How to get return value using callBackMethod in Directive?
While calling the controller's function from inside a directive with an isolate scope, you need to pass an object:
HTML
<div ng-app="myApp" ng-controller="ctrl">
<div abc-option get-display-name="getDisplayName(columnName)"></div>
</div>
JS
var app = angular.module('myApp', []);
function ctrl($scope){
$scope.getDisplayName = function(columnName) {
return 'abc';
};
}
app.directive('abcOption', function($compile,$timeout) {
return {
restrict : 'A',
template : '<div class="filter-content">abc</div>',
replace : true,
scope : {
callBackMethod:'&getDisplayName'
},
link: function(scope,element,attrs){
/* send an object to the function */
console.log(scope.callBackMethod({columnName:"hurray"}));
}
};
});
Fiddle
The answer from CodeHater works but is (just a little) confusing. So I updated it to make it easier to understand
HTML
<div ng-app="myApp" ng-controller="ctrl">
{{returnVal}}
<div abc-option callback="setDisplayNameFn(mustBeTheSame)"></div>
</div>
JS
var app = angular.module('myApp', []);
function ctrl($scope){
$scope.setDisplayNameFn = function(whatever) {
$scope.returnVal= whatever;
};
}
app.directive('abcOption', function($compile,$timeout) {
return {
restrict : 'A',
template : '<div class="filter-content"><b>directive html<b></div>',
replace : true,
scope : {
callBackMethod:'&callback'
},
link: function(scope,element,attrs){
/* send an object to the function */
console.log(scope.callBackMethod({mustBeTheSame:"value from directive"}));
}
};
});
updated fiddle
My initial goal was to create components that have input definitions in them, and collect everything back on the parent controller. There are hacky methods that I've had to use to accomplish this ($rootScope, $on), but I would like to know where I went wrong in my code. This is about two-way binding between directives and controllers ("=")
my view:
<div ng-app="app" ng-controller="myCtrl">
my input value: {{variable}}
<div my-directive input="variable"></div>
</div>
my controller/directive
angular.module("app",[])
.controller("myCtrl", function($scope){
$scope.variable = "initial value";
})
.directive("myDirective", function(){
return {
scope: { eggplant: "=input" },
template: "Change the parent value: <input ng-model='eggplant'/>" +
"<br> eggplant: {{eggplant}}"
}
});
For whatever reason, this doesn't work. I've tried some other configurations on the template, such as...
...
template: "Change the parent value: <input ng-model='{{eggplant}}'/>"
...
...
template: "Change the parent value: <input ng-model='{eggplant}'/>"
...
But ultimately, I've had to add a controller (with $scope) to the directive, add a ng-change function, and when the directive changes, attach that to the directive controller $scope... But this doesn't feel like the right way to approach this problem. Can anyone reveal where I went wrong?
...
.directive("myDirective", function(){
return {
scope: { eggplant: "=input" },
template: "Change the parent value: "+
"<input ng-model='eggplant' ng-change='change(eggplant)'/>",
controller: function($scope){
$scope.change(val){
// I also have a $rootscope hack I can sell you :P
$scope.eggplant = val;
}
}
}
});
Thanks for your help!
Your directive looks off. In your scope, you want to assign eggplant to input in this case, not variable:
.directive("myDirective", function(){
return {
scope: { eggplant: "=input" },
template: "Change the parent value: <input ng-model='eggplant'/>" +
"<br> eggplant: {{eggplant}}"
}
})
You're telling the directive to bind on the attribute, not the value name.