AngularJS: Passing function to directive - javascript

I got a problem by passing a function to a directive ( familiar to this post: AngularJS - pass function to directive but i can´t get it working)
Here is my Code:
Directive:
.directive('testdirective', function(){
return{
restrict: 'E',
scope: {
onClick: '&'
},
controller: 'TestController',
controllerAs: 'tc',
bindToController: true,
template: '<div><button ng-click="onClick()">What UP</button></div>',
replace: true
}
})
Controller:
TestController.$inject = ["$scope"];
function TestController($scope) {
$scope.testFunction = function(){
alert("I´m the alert of the TestContoller");
};
$scope.test = 'test';
}
HTML:
<div>
<testdirective on-click="testFunction()"></testdirective>
</div>
What I want sounds very simple, I just want to pass the function to the directive and execute it with the ng-click on the button.
For me my code looks exactly like this fiddle
but mine is not working :/
Would be awesome if someone got some hints for me.
EDIT
My directive will need his own controller !
Later the function to be passed in will come from another controller !!!

The fiddle is not the same as your code.
You have set the controller of your directive to be "TestController". I assume what you wanted to do was:
.directive('testdirective', function(){
return{
restrict: 'E',
scope: {
onClick: '&'
},
template: '<div><button ng-click="onClick()">What UP</button></div>',
replace: true
}
});
and in your HTML,
<div ng-controller="TestController">
<testdirective on-click="testFunction()"></testdirective>
</div>
EDIT: Based on OP's comment
app.directive('testdirective', function(){
return{
restrict: 'E',
scope: {
onClick: '&'
},
template: '<div><button ng-click="tc.onClick()">What UP</button></div>',
replace: true,
controller: 'TestController',
controllerAs: 'tc',
bindToController: true
}
});
app.controller('TestController', function ($scope) {
console.log($scope);
}) ;
app.controller('AnotherController', function ($scope) {
$scope.testFunction = function(){
alert("I´m the alert of the TestContoller");
};
$scope.test = 'test';
});
And, your HTML
<div ng-controller="AnotherController">
<testdirective on-click="testFunction()"></testdirective>
</div>
You are telling the directive to bindToController. So within the directive's template, onClick is bound to the controller and not the scope. So, you access the onclick via the controller as tc.onClick() in the directive's template.

You may want to pass a method as a reference:
1.Pass the function as a reference and not a call:
<div>
<testdirective on-click="testFunction"></testdirective>
</div>
2.Update the directive:
.directive('testdirective', function(){
return{
restrict: 'E',
scope: {
onClick: '='
},
template: '<div><button ng-click="onClick()">What UP</button></div>',
replace: true
}
});
JSFIDDLE.

Well, in your testdirective,you defined controller TestController.
The testFunction() that you try to calling via onClick directive scope parameter is defined in controller TestController which is directive controller.
So, rather than calling via onClick you can call directly like
template: '<div><button ng-click="testFunction()">What UP</button></div>'.
Its very confusing ,you defining controller in directive and again referring it's one function via same directive's scope parameter which look like recursive.
If you want to call via directive scope parameter then you should do belowe changes.
for e.g.
JS :
<div ng-controller="TestController" ng-app="dr">
<testdirective on-click="testFunction()"></testdirective>
</div>
app.directive('testdirective', function() {
return{
restrict: 'E',
scope: {
onClick: '&'
},
template: '<div><button ng-click="onClick()">What UP</button></div>',
replace: true
}
});

Directivie:
.directive('testdirective', function(){
return{
restrict: 'E',
scope: {
onClick: '=onClick'
},
controller: 'TestController',
controllerAs: 'tc',
bindToController: true,
template: '<div><button ng-click="onClick()">What UP</button></div>',
replace: true
}
})
use '=' instead of '&' so you can fetch the html function in your directive. and you can simply pass onClick parameter through HTML
HTML:
<div>
<testdirective on-click="testFunction()"></testdirective>
</div>

Related

bindToController Angular 1.6

I have an issue with my directive after migration to lastest angular.
.directive('documentGrid',
function() {
return{
restrict: 'EA',
scope: {
documentData: '=',
remove: '&',
edit: '&',
documentDatasources: '='
},
controller: 'DocumentCrtl',
controllerAs: 'vmDocument',
//bindToController: true,
//transclude: true,
templateUrl: '/Custom/Document/document.cshtml'
};
});
<div class="box" document-grid document-data="widget"
document-datasources="vm.datasource.data"
remove="vm.remove(item)"
edit="vm.openSettings(item,datasources)">
</div>
before move to lastest version it works fine with bind controller set to true but now it does't work. So I remove the bindToController : true and I need to use $scope to access to my varibile bind from html directive
I read guide, post and tutorial about directive but I don't find any solution.
Try to replace with this:
directive('documentGrid',
function() {
return{
restrict: 'EA',
bindToController: {
documentData: '=',
remove: '&',
edit: '&',
documentDatasources: '='
},
controller: 'DocumentCrtl',
controllerAs: 'vmDocument',
scope: {},
//transclude: true,
templateUrl: '/Custom/Document/document.cshtml'
};
});
Note that I changed bindToController and scope.
Then in your controller your must bind this, e.g.: var vm = this; at the first line of your controller preferably.
Finally you will be able to access your data in controller like this:
vm.documentData
See this fiddle: https://jsfiddle.net/2n5skwqj/794/
In the controller function I log the name.

Using service inside directive?

I am learning how to create custom directives.
My service looks like that:
myApp.service('myService',function(){
this.myFunction=function(myParam){
// do something
}
});
Here is my directive:
myApp.directive('myDirective',function(myService){
return {
restrict: 'E',
scope: {
param: '=myParam',
},
template: '<button ng-click="myService.myFunction(param)">Do action</button>',
}
});
In HTML, when I use <my-directive my-param="something"></my-directive> it properly renders as a button. However when I click it, myService.myFunction, doesn't get executed.
I suppose I am doing something wrong. Can someone give me a direction?
I guess this has something to do with the directive's scope.
The service wont be available directly inside the template. You'll have to use a function attached to the directive's scope and call the service function from within this function.
myApp.directive('myDirective',function(myService){
return {
restrict: 'E',
scope: {
param: '=myParam',
},
template: '<button ng-click="callService(param)">Do action</button>',
link: function(scope, element, attrs) {
scope.callService = function() {
myService.myFunction();
}
}
}
});
It doesn't work because in your example a directive doesn't actually know what is myService. You have to explicitly inject it e.g.:
myApp.directive('myDirective', ['myService', function(myService){ ... }]);
See also this question or this question.
You should use a controller to do all DOM-modifications.
See this plunkr: https://plnkr.co/edit/HbfD1EzS0av5BG6NgtIv?p=preview
.directive('myFirstDirective', [function() {
return {
'restrict': 'E',
'controller': 'MyFirstController',
'controllerAs': 'myFirstCtrl',
'template': '<h1>First directive</h1><input type="text" ng-model="myFirstCtrl.value">'
};
}
You can inject the service in the controller and then call that function inside your template:
Inject myService into controller:
myApp.controller("ctrl", function($scope, myService) {
$scope.doService = function(myParam) {
return myService.myFunction(myParam);
};
});
Call doService method of the controller inside your template:
myApp.directive('myDirective',function(){
return {
restrict: 'E',
scope: {
param: '=myParam',
},
template: '<button ng-click="doService(param)">Do action</button>',
}
});

How to pass a value into a directives controller in angular?

My directive has a controller and I am trying to figure out how to pass a value from the directive that was passed in. In the example below 'name' is not valid posted to the console but it shows in the html when rendered. Obviously my example is an over simplication, but you get the point.
angular.module('myApp')
.directive('helpLabel', function() {
return {
restrict: 'E',
scope: {
name: '#',
},
template: '<span>{{name}}</span>',
controller: function ($scope) {
console.log(name);
}
};
});
<helpLabel name="test"></helpLabel>
The answer I found is to use bindToController along with controllerAs now effective angular 1.4.
angular.module('myApp')
.directive('helpLabel', function() {
return {
restrict: 'E',
scope:{},
bindToConroller: {
name: '#',
},
template: '<span>{{cntrl.name}}</span>',
controller: function () {
console.log(cntrl.name);
},
controllerAs: "cntrl"
};
});
http://blog.thoughtram.io/angularjs/2015/01/02/exploring-angular-1.3-bindToController.html
This is because when it is being rendered to the html, you encapsulated name within {{}}. If you wan't to access the name property within your directive you have to change your code.
angular.module('myApp')
.directive('helpLabel', function() {
return {
restrict: 'E',
scope: {
name: '#',
},
template: '<span>{{name}}</span>',
controller: function ($scope) {
console.log($scope.name);
}
};
});
In your code, console.log(name);, the variable name is not known your directive and hence not able to access it, but since angular has done binding to 'name' variable, it can render {{name}}.
You should access variable name as $scope.name as variable name is present inside current scope.
Modify your code as follow:
angular.module('myApp')
.directive('helpLabel', function() {
return {
restrict: 'E',
scope: {
name: '#',
},
template: '<span>{{name}}</span>',
controller: function ($scope) {
console.log($scope.name);
}
};
});

Pass parameters from html directive to controller

I would like to pass an argument from an html directive to a controller
Example:
Directive:
angular.module('app')
.directive('helloWorld', function () {
return {
replace: false,
restrict: 'AE',
templateUrl: "./views/templates/helloWorld.html"
}
});
helloWorld.html:
<body ng-app="app" >
<div ng-controller="HelloWorldCtrl">
{{ welcome }}
</div>
hello.html:
<body ng-app="app">
<hello-world/>
</body>
HelloWorldCtrl:
angular.module('app')
.controller('HomeWorldCtrl', function ($scope, ) {
$scope.welcome = "Welcome"
};
})
Can I specify a parameter in hello.html e.g.
<hello-world param="param1"/>
That is being passed into the controller?
So in the HomeWorldCtrl I can check the value of the parameter?
Are there any better alternatives to achieve this?
Thanks,
app.directive('helloWorld', function(){
return {
restrict:'E',
scope: {
param: '#'
},
template:'<div class="param"><h2>{{param}}</h3></div>'
};
});
// you have options to choose from
//= is two-way binding
//# simply reads the value (one-way binding)
//& is used to bind functions
<hello-world="someParam"></hello-world>
// for the scope definition:
scope: {
title: '#helloWorld'
}
The usage in the template will remain the same
<hello-world param="someParam"></hello-world>
If you isn't use isolated scope (scope: {someparam: ""}), then you may use any $scope properties in the directive template without changing anything:
$scope.param = "new param value";
..
return {
..
,template: "<param>{{param}}</param>"
Thanks!
directive
return {
replace: false,
restrict: 'AE',
templateUrl: "./views/templates/PatientSearchEdit.html",
scope: {
param: '#'
}
}
controller
console.log($scope.param);
Logs indeed the value specified.
Thanks you very much!

How to make two way binding between angular directives without using "dots"

Suppose, I have controller:
angular.module('tf').controller('Ctrl', function($scope){
$scope.params = {
orderBy: null
};});
And a directive "common":
angular.module('tf').directive("common", function() {
return {
restrict: 'E',
replace: true,
template: '<div><outer order-by="orderBy"><inner order-by-field="name1"></inner><inner order-by-field="name2"></inner></outer></div>',
controller: function ($scope) {
},
scope: {
orderBy: '='
},
link: function (scope, element, attrs) {
}
}});
Controller is using directive within it's template:
<div ng-app="tf">
<div ng-controller="Ctrl">
<common order-by="params.orderBy"></common>
<div style="color:red">{{params.orderBy}}</div>
</div>
This directive is using directive "outer":
angular.module('tf').directive("outer", function() {
return {
restrict: 'E',
transclude: true,
replace: true,
template: '<div ng-transclude></div>',
controller: function ($scope) {
this.order = function (by) {
$scope.orderBy = by
};
},
scope: {
orderBy: '=',
}
}});
Which is parent for the directive "inner":
angular.module('tf').directive("inner", function() {
return {
require: '^outer',
restrict: 'E',
transclude: true,
replace: true,
template: '<div ng-click="onClicked()">{{orderByField}}</div>',
controller: function ($scope) {
$scope.onClicked = function () {
$scope.outer.order($scope.orderByField);
}
},
scope: {
orderByField: '#'
},
link: function (scope, element, attrs, outer) {
scope.outer = outer;
}
}});
The directive "outer" shares "order" method with directive "inner" by it's controller. The directive "inner" is accessing it by using "require" mechanism.
For some reason, this is not working as expected (Property of the controller isn't updated each time it's changed by directive). If I place "orderBy" into object (e.g. {"order": {"by": null }} ) and use object instead of string value, everything is working as expected ( controller scope is properly updated by the directive). I know about "always use dots" best practices principle, but I don't wanna use it here, because it would make my directive's API less intuitive.
Here is jsfiddle:
http://jsfiddle.net/A8Vgk/1254/
Thanks

Categories