22

My style of writing angular controllers is like this (using controller name instead of function)

angular.module('mymodule', [
])
    .controller('myController', [
        '$scope',
        function($scope) {
            // Some code here

        }
    ]);

What I need now is when providing i routes I want to define resolve part:

 $routeProvider.when('/someroute', {
        templateUrl: 'partials/someroute.html', 
        resolve: myController.resolve}) // THIS IS THE CRITICAL LINE

Since controller is defined as a name how to accomplish resolve part bellow?

To clarify more in details I want to load some data from server before route is resolved and then use these data in controller.

UPDATE: To be more precise I want each module has its "resolve" function that will be called before root with that controller is executed. Solution in this post (answered by Misko Hevery) does exactly what I want but I don't have controllers as functions but as a names.

Community
  • 1
  • 1
Andrej Kaurin
  • 11,592
  • 13
  • 46
  • 54

4 Answers4

24

The controller definition and resolve parts are to be specified separately on the route definition.

If you define controllers on a module level you need to reference them as string, so:

 $routeProvider.when('/someroute', {
        templateUrl: 'partials/someroute.html', 
        controller: 'myController',
        resolve: {
          myVar: function(){
            //code to be executed before route change goes here
          };
        });

The above code also shows how to define a set of variables that will be resolved before route changes. When resolved those variables can be injected to a controller so taking the example from the snippet above you would write your controller like so:

.controller('myController', ['$scope', 'myVar', function($scope, myVar) {
            // myVar is already resolved and injected here
        }
    ]);

This video might help as well: http://www.youtube.com/watch?v=P6KITGRQujQ

Christoph
  • 26,519
  • 28
  • 95
  • 133
pkozlowski.opensource
  • 117,202
  • 60
  • 326
  • 286
  • @AndrejKaurin you can inject services to both your controller and resolve functions, if this is what you are asking... Could you be more precise? – pkozlowski.opensource Feb 21 '13 at 12:27
  • Inside when(), should `'myController',` be `controller: 'myController',`? – Mark Rajcok Feb 26 '13 at 04:18
  • @MarkRajcok indeed. Fixed it. – Christoph Apr 15 '13 at 15:38
  • @pkozlowski.opensource I get an error about myVarProvider is unknown. Any ideas why? – Jon May 22 '13 at 19:20
  • What version are you using? – Cybrix May 31 '13 at 12:56
  • What's exactly the meaning of the resolve key? "myVar" in this Case? – piotr Sep 06 '13 at 12:30
  • I too get provider unknown when I provide a string for the `controller` attribute of the route. However if I use a function instead, the resolve attribute gets injected in successfully and everyone is happy. – Mark Oct 21 '13 at 12:11
  • I just went through this same problem and found the answer here: https://groups.google.com/forum/#!topic/angular/6nA4MEKyKAc - basically I also needed to remove the ng-controller from my view and let the route add it along with the resolved data – headwinds Jan 12 '14 at 19:27
  • Awesome, i didn't know that i can inject variable from resolve section of the route directly into controller, i was using $route['current']['locals'] to get the variable from resolve definition – Goran Radulovic Mar 18 '14 at 09:53
  • @pkozlowski.opensource is it possible to add multiple controllers in the resolve such that `controller: 'myController', 'secondController`, `thirdController` ? – bouncingHippo May 16 '16 at 14:35
13

@pkozlowski.opensource 's answer works, but I don't really want to mess up my routing and and controllers, because I always keep it separated (from Yo Generator). Actually, we can also have controller and resolve(r) all as string/name (NOT function).

angular.module('mymodule', [
])
  .controller('myController', [
      '$scope', 'myModelCombination'
      function($scope, myModelCombination) {
          // myModelCombination[0] === (resolved) myModel 
          // myModelCombination[1] === (resolved) myModel2

      }
  ])
  .controller('myController2', [
      '$scope', 'myModel'
      function($scope, myModel) {
          // Some code here

      }
  ])
  .factory('myModel', [
      '$scope',
      function($scope) {
          // return a promise

      }
  ])
  .factory('myModel2', [
      '$scope',
      function($scope) {
          // return a promise

      }
  ])
  .factory('myModelCombination', [
      '$scope', 'myModel', 'myModel2'
      function($scope) {
          return $q.all(['myModel', 'myModel2']);

      }
  ]);

Then in your routing file this should be added

$routeProvider.when('/someroute', {
    templateUrl: 'partials/someroute.html', 
    resolve: ['myModel'] //ALWAYS IN ARRAY)
});
$routeProvider.when('/myModelCombination', {
    templateUrl: 'partials/someroute2.html', 
    resolve: ['myModel'] //ALWAYS IN ARRAY)
});

http://docs.angularjs.org/api/ng.$routeProvider

TruongSinh
  • 4,662
  • 32
  • 52
  • 2
    myModel factory should return promise? Then how to return more promises via single factory (myModel in this case)? Or I should create new factory for every resolve. – Andrej Kaurin Aug 12 '13 at 22:59
  • 1
    Yes, each factory should return one and only one thing, either value or promise, unless you want to wait for everything and return all of it in $q.all(). Answer edited. – TruongSinh Jan 19 '14 at 19:54
  • This doesn't seem to work. Can you a show a fiddle? – Dan May 17 '17 at 23:31
1

This would work too

var MyController = myApp.controller('MyController', ['$scope', 'myData', function($scope, myData) {
  // Some code here
}]);

MyController.resolve = {
  myData: ['$http', '$q', function($http, $q) {
    var defer = $q.defer();

    $http.get('/foo/bar')
      .success(function(data) {
        defer.resolve(data);
      })
      .error(function(error, status) {
        defer.reject(error);
      });

    return defer.promise;
  }]
};
schneikai
  • 289
  • 1
  • 10
0

@TruongSinh answer worked for me and is way nicer than having additional functions in the router. I tweaked it a little as it was returning the deferred object instead of the actual resolved data.

$routeProvider.when('/someroute', {
    templateUrl: 'partials/someroute.html', 
    controller: 'SomeController',
    resolve: {
       myModel: 'myModel'
    }
});
Mark
  • 26
  • 2
  • 3
    Would it be possible to post your entire solution here? I'm trying to do the same thing (returning a deferred object on resolve) and having difficulties to get it to work. Thanks. – Pinny Aug 09 '14 at 03:56