0

I am migrating an AngularJS multiple-page app to a single-page app, and I am having some trouble to replicate the following behaviour:

Each HTML file has a different base controller and a ng-view. For example, file1.html looks like this:

<body ng-controller="BaseCtrl1">
  <!-- Routes to /view11, /view12, etc. with their corresponding controllers -->
  <div ng-view></div>
</body>
<script src="file1.js"></script>

file2.html uses BaseCtrl2, routing to /views21, /view22 and so on. Each of this controllers initialize the scope, and the corresponding subset of views share this part of the model:

file1.js:

module.controller('BaseCtrl1', function($scope, ServiceA, ServiceB, ServiceC) {
  // Populate $scope with ServiceN.get() calls
  ServiceA.get(function(response) {
    $scope.foo = response.results;
  });
});
// ...

file2.js:

module.controller('BaseCtrl2', function($scope, ServiceX, ServiceY) {
  // Populate $scope with ServiceN.get() calls
});
// ...

However, with a single-page app I cannot use a fixed parent controller (declared in the body element) for each different group of views. I have tried using the $controller service like in the answer of this question, but I need to inject all the dependencies of the parent in the child controller, and does not look like a neat solution at all:

module.controller('View11Ctrl', function($scope, ServiceA, ServiceB, ServiceC) {
  $controller('BaseCtrl1', {/* Pass al the dependencies */});
});

module.controller('View12Ctrl', function($scope, ServiceA, ServiceB, ServiceC) {
  $controller('BaseCtrl1', {/* Pass al the dependencies */});
});

I would like to know if there is a way to replicate the original behaviour by initializing a "common" part of the scope of a group of views, and maintain it when changing the route.

Community
  • 1
  • 1
A. Rodas
  • 20,171
  • 8
  • 62
  • 72
  • 1
    Have you looked at [AngularJS Inheritance Patterns](http://blog.mgechev.com/2013/12/18/inheritance-services-controllers-in-angularjs/) ? – Tassos Bassoukos Sep 23 '14 at 10:04
  • Further, it looks to me that you can completely reuse the same function in all controller methods. – Tassos Bassoukos Sep 23 '14 at 10:07
  • 1
    Also, you can have nested controllers - f.e. have BaseCtrl1 on the outer tag and have View11Ctrl only set the differences. Scopes are inherited. – Tassos Bassoukos Sep 23 '14 at 10:08
  • @TassosBassoukos This mechanism looks similar to the `$controller('BaseCtrl1', ...)` approach, since in the end you have to inject all the dependencies again to the child controller to pass it to the base controller (`BaseCtrl.call(this, ...`), and this is something I want to avoid - there are 8/10 services to inject, and I would have to declare them even if I don't use it in the rest of the child controller. – A. Rodas Sep 23 '14 at 10:16
  • @TassosBassoukos I am already nesting the controllers (and inheriting the scope), the problem is that the base one should change depending on the view. – A. Rodas Sep 23 '14 at 10:18

1 Answers1

1

You can use $injector.invoke() service method to achieve this.

module.controller('View11Ctrl', function($scope, ServiceA, ServiceB, ServiceC) {
  $injector.invoke(BaseCtrl1, this, { $scope: $scope });
}

The third argument is defined as:

If preset then any argument names are read from this object first, before the $injector is consulted.

This way you only need to pass the locals to your base controller that is specific to your child controller, and all other base controller dependencies will be resolved using the normal $injector DI.

Beyers
  • 8,968
  • 43
  • 56
  • The use of $injector is an improvment over the $controller approach. However, I am also looking for the "best practice" solution, so I'd like to know how common is its use (I haven't seen any example where these services are used in every controller). – A. Rodas Sep 24 '14 at 06:35