1

I have a controller name as string and I want to get constructor of it.

My current method is using $controller as below:

$scope.myControllerConstructor= $controller( "myControllerName" , {$scope: $scope.$new()}).constructor;

Later on, I use this constructor in the html like this:

<div ng-controller="myControllerConstructor">

The issue is my controller runs two time, one time when I get the constructor (which is wrong) and one time when my html gets compiled (which is correct)

The question is how to get the controller constructor without running it?


Update about use-case: In our application we have many pages with 60% similarities and 40% different activities. I created a directive for those pages and other developers in the team are using my directive to create their page.

The directive accepts a template and a controller (I get them as string) and later on I include the provided template and controller as below:

<div ng-include="myTemplate" ng-controller="myControllerConstructor"></div>

Please take a look at this jsfiddle for a simple example of issue.

9
  • Approach doesn't make much sense. What higher level problem are you trying to solve? Commented Apr 21, 2017 at 22:35
  • If you're using it for controller inheritance, I would suggest to update the title and the question to match your case, this would make it clear and easier to find on SO. Commented Apr 22, 2017 at 1:00
  • The delayed instatiation API is private and not intended to be used by applications. There are many ways to abuse the AngularJS framework. Using it in an unstructured manner often results in a fragile application that is a maintenance nightmare. So what is your use case? Maybe there is a better structured way to accomplish it. Commented Apr 22, 2017 at 17:37
  • @charlietfl I updated the use-case Commented Apr 24, 2017 at 14:41
  • still doesn't explain the concept behind trying to use myControllerConstructor. Are you wanting to evaluate ng-controller attribute to dynamically add controller? Suggest you provide a demo that gives an indication of the issue Commented Apr 24, 2017 at 14:48

2 Answers 2

1
+50

The structure of your code looks ok but the issue is $controller( "myControllerName" , {$scope: $scope.$new()}) already instantiate the controller with the given scope for you.

It is true that you can access the controller constructor with .constructor but it is too late as you already created an instance of the controller.

ng-controller does the exact same thing as $controller( "myControllerName" , {$scope: $scope.$new()})

When a Controller is attached to the DOM via the ng-controller directive, AngularJS will instantiate a new Controller object, using the specified Controller's constructor function. A new child scope will be created and made available as an injectable parameter to the Controller's constructor function as $scope.

To solve this issue you should pass the controller constructor function to pageDirectiveTemplate instead of the controller name.

The working fiddle

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

Comments

0

There is a different way we can achieve this. In directive, while using isolated scope (like you are doing here in fiddle), you could have a property controller that has value "@" and have another name property having the value of "myController" or whatever your controller name you are passing as.

So, your directive could look something like this:

app.directive('pageDirective', function() {
  return {
    restrict: "A",
    templateUrl: "pageDirectiveTemplate",
    scope: {
      myTemplate: "@"
    },
    controller: "@",
    name: "myController"
  }
});

Notice that, only change in HTML would be to have the directive as an attribute instead of an element. So,

<div page-directive my-template="templateA" my-controller="controllerA">
</div>
<div page-directive my-template="templateA" my-controller="controllerB">
</div>

This would give you exactly what you are looking for. Now you can have same template pointing different controllers and vice-versa.

working fiddle | Note that it works for two different controllers having same template. Also, check the console to see how it logs only once from each controller.

3 Comments

It is nice, but the issue is we are sharing the controller with "pageDirectiveTemplate" and "templateA". pageDirectiveTemplate controller is static and has shared logic in it. however, myController is dynamic.
@Arashsoft, oh shoot.. So let me get this clear.. You want to share a dynamic controller (say controllerA) with a static one (pageDirectiveTemplate) for some dynamic template. Right?
"pageDirective" has its own controller and template (they are static). Inside the "pageDirectiveTemplate", I want to inject a dynamic template with dynamic controller. Currently I am using <div ng-include="myTemplate" ng-controller="myControllerConstructor"></div> which works fine but the controller runs two time.

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.