4

Lets say I have the following HTML structure:

<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>

Inside ng-controller="controller3" there is a custom directive.

The directive is as followed:

ang.directive("testDirective", function() {
    return {
        restrict: 'AE',
        link: function (scope, elem, attrs) {
            console.log(scope);
        },
        template: "<h3>I return $scope.controller3</h3>"
    }
});

The $scope now holds the data from ng-controller="controller3". How can i link a custom controller to it? So instead the directive passes its parent controller, I want too pass for example controller1 its data.

I have to be able to pass any controller to it, because the directive is depended on the data inside a given controller.

I cannot replace the <test-directive> inside the required controller

Here a fiddle 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 <ng-pagination></ng-pagination> anywhere on the page.

The directive creates a pagination from a given dataset. The dataset however can hold anything. It doens't depend on values or whatever.

There is only one requirement for the directive. It looks inside the controller if it has a $scope called $scope.result. The $scope.result gets filled with data from an API call.

The pagination then recreates a object with 10 results per page.

The problem I have is: The ng-controller can be anywhere on the page also can the <ng-pagination></ng-pagination>.

What i want to archieve is something like this:
I assign an data attribute to the [ng-pagination]. Called: data-controller. You can then pass the controller name to it. The directive then has access to all the data inside that controller.

It would then look like this:
<ng-pagination data-controller="controller1" show-next="true" ...></ng-pagination>


UPDATE

I found out that you can assign a controller by doing:

ang.directive("directive", function() {
    return {
        controller: "[CONTROLLER NAME]"
    }
});

I though, perhaps this is possible:

ang.directive("directive", function() {
    return {
        controller: "{{controller}}",
        link: function (scope, elem, attrs) {
            $scope.controller = "[CONTROLLER NAME]"
        }
    }
});

However, it gives me the error:

Error: ng:areq Bad Argument
Argument '{{controller}}' is not a function, got undefined

7
  • Take a look at scope properties - You need to access $scope.$parent Commented May 18, 2017 at 10:22
  • Thanks for the awnser. I cannot use $parent. Its not as simple as that. Because the controller can be anywhere on the page. Also, if you look the snippet you can see the $parent doens't hold any controller data. As far as i can see. Commented May 18, 2017 at 10:24
  • Oh, I thought they are nested. So you can't pass controller1 from controller3 because they have completely different scope, you could use $rootScope which I don't recommend, but you can use a factory - Let me know if this question helps, and I'll mak yours as duplicate Commented May 18, 2017 at 10:43
  • Thanks for the reply, the link to the question im familair with. But its not about sharing data between controllers or any kind. What i need is some $scope variables. For example: $scope.data. So what i want is, when you call the directive, you asign a controller to it, which has the $scope.data. The directive is depending on that variable. Is there no way i can do someting like controller="controller1"? Commented May 18, 2017 at 11:22
  • 1
    See updated question. Explained the real case scenario. Commented May 18, 2017 at 11:36

1 Answer 1

1

I was playing with controller as seen in my update, and reading this guide. I came up with below solution

So how can you pass any controller to a directive?

  • You first have to isolate the scope with scope: {}
  • Set the controller property inside the directive with controller: "@". You can now assign values to it with the next step
  • Set the property name: "controller". Ill explain how to use this below.

I have been told isolating the scope is necessary, it does work without however.

If you now place the directive you can now assign any controller to it by doing:

<ng-pagination data-controller="[CONTROLLER NAME]>

The name of the property name doens't matter. So if you want to call it, assign-any, you can pass that 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 to read this guide for a well explained tutorial on how to work with directives.

Part one and Part two

Sign up to request clarification or add additional context in comments.

Comments

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.