How do I bind a controller to a directive in AngularJS?
Let's say I have the following structure HTML
:
<div ng-app="testApp">
<div ng-controller="controller1">
{{controller1}}
</div>
<div ng-controller="controller2">
{{controller2}}
</div>
<div ng-controller="controller3">
{{controller3}}
<test-directive></test-directive>
</div>
</div>
There ng-controller="controller3"
is a custom directive inside .
The directive is as follows:
ang.directive("testDirective", function() {
return {
restrict: 'AE',
link: function (scope, elem, attrs) {
console.log(scope);
},
template: "<h3>I return $scope.controller3</h3>"
}
});
Now $scope
contains data from ng-controller="controller3"
. How can I bind a custom controller to it? So instead the directive passes its parent controller, I want to also pass, for example controller1, its data.
I need to pass any controller because the directive depends on the data inside the given controller.
I cannot replace <test-directive>
inside the required controller
Here you can play with
var ang = angular.module('testApp', []);
ang.controller("controller1", controller1);
function controller1($scope) {
$scope.controller1 = "controller1";
}
ang.controller("controller2", controller2);
function controller2($scope) {
$scope.controller2 = "controller2";
}
ang.controller("controller3", controller3);
function controller3($scope) {
$scope.controller3 = "controller3";
}
ang.directive("testDirective", function() {
return {
restrict: 'AE',
link: function (scope, elem, attrs) {
console.log(scope);
},
template: "<h3>I return $scope.controller3</h3>"
}
});
<script src="https://cdnjs.cloudflare.com/ajax/libs/angular.js/1.5.5/angular.min.js"></script>
<div ng-app="testApp">
<div ng-controller="controller1">
{{controller1}}
</div>
<div ng-controller="controller2">
{{controller2}}
</div>
<div ng-controller="controller3">
{{controller3}}
<test-directive></test-directive>
</div>
</div>
Real case scenario:
I made a pagination directive . You can call the directive by placing it <ng-pagination></ng-pagination>
anywhere on the page.
The directive creates pagination from the given dataset. However, a dataset can contain anything. It doesn't depend on values, etc.
There is only one requirement for a directive ... It looks inside the controller if it has a $scope
called $scope.result
. $scope.result
populated with data from the API call.
Then pagination is recreated object
with 10 results per page.
I have a problem: ng-controller
can be anywhere on the page can also <ng-pagination></ng-pagination>
.
What I want to archive looks something like this:
I assign a data attribute to [ng-pagination]
. Called: data-controller
. Then you can pass the controller name to it. The directive then has access to all data within that controller.
It will look like this: <ng-pagination data-controller="controller1" show-next="true" ...></ng-pagination>
UPDATE
I found out that you can assign a controller by following these steps:
ang.directive("directive", function() {
return {
controller: "[CONTROLLER NAME]"
}
});
Although it is possible it is possible:
ang.directive("directive", function() {
return {
controller: "{{controller}}",
link: function (scope, elem, attrs) {
$scope.controller = "[CONTROLLER NAME]"
}
}
});
However, this gives me an error:
Error: ng: areq Bad argument The
argument '{{controller}}' is not a function, got undefined
source to share
I was playing with controller
as shown in my update and reading this guide . I came up with a solution below
So how can you pass anyone controller
to directive
?
- First you need to highlight
scope
withscope: {}
- Set the controller property inside the directive with
controller: "@"
. Now you can assign values ββto it with the following step - Set the property
name: "controller"
. I will explain how to use this below.
I was told isolating
that the area is necessary, but it works, however.
If you post now directive
, you can now assign any controller to it by doing the following:
<ng-pagination data-controller="[CONTROLLER NAME]>
The property name name
doesn't matter. So if you want to call it, assign-any
you can pass it attribute
by setting the property name
as name: assignAny
.
var ang = angular.module('testApp', []);
ang.controller("controller1", controller1);
function controller1($scope) {
$scope.controller1 = "Yay, im now part of the directive!!!";
}
ang.controller("controller2", controller2);
function controller2($scope) {
$scope.controller2 = "controller2";
}
ang.controller("controller3", controller3);
function controller3($scope) {
$scope.controller3 = "controller3";
}
ang.directive("testDirective", function() {
return {
restrict: 'AE',
link: function (scope, elem, attrs) {
scope.controller = attrs.controller;
console.log(scope);
},
template: "<h3>I return {{controller}}</h3>",
controller: "@",
name: "controller",
}
});
<script src="https://cdnjs.cloudflare.com/ajax/libs/angular.js/1.5.5/angular.min.js"></script>
<div ng-app="testApp">
<div ng-controller="controller1">
{{controller1}}
</div>
<div ng-controller="controller2">
{{controller2}}
</div>
<div ng-controller="controller3">
{{controller3}}
<test-directive data-controller="controller1"></test-directive>
</div>
</div>
I recommend reading this guide for a well explained tutorial on how to work with directives.
Part one and part two
source to share