Loukas Avramidis
Loukas Avramidis

Reputation: 537

Using $scope in ui-router resolve

I am using ui-router resolve in order to get some data from a service.

The thing is that I need to get a value from the parent $scope in order to call the service as shown bellow.

resolve: {
              contactService: 'contactService',
              contacts: function ($scope, contactService) {
                  return contactService.getContacts($scope.parentCtrl.parentObjectId);
              }
          }

I keep getting Error: [$rootScope:infdig] 10 $digest() iterations reached. Aborting!

Also tried a few desperate attempts such as adding scope to the resolve object as shown bellow with not success.

scope: $scope

Any ideas?

Upvotes: 16

Views: 11749

Answers (2)

redben
redben

Reputation: 5686

As an alternative to the accepted solution, which requires another round trip to the server for the same resource (if you are getting the value from the server/api) you could $watch the parent from the child controller.

function ParentController($http) {
  var vm = this;
  $http.get(someResourceUrl).then(function(res) {
    vm.someResource = res.data;
  });
}

function ChildController($scope) {
  // wait untill the parent gets the value
  var unwatch = $scope.$watch('parent.someResource', function(newValue) {
    if (newValue) {
      // the parent has the value, init this controller
      init(newValue);
      // dispose of the watcher we no longer need
      unwatch();
    }
  });
  function init(someResource) {
    // ... do something
  }
}

function routerConfig($stateProvider) {
  $stateProvider
    .state('parent', {
      url: '/parent',
      controller: 'ParentController',
      controllerAs: 'parent',
      templateUrl: '...',
    })
    .state('parent.child', {
      url: '/child',
      controller: 'ChildController',
      controllerAs: 'child',
      templateUrl: '...',
    });
}

Upvotes: 0

iH8
iH8

Reputation: 28638

That's impossible, scope hasn't been initialized at that point so you can't use it in the resolve object. You can access the scope in the controller after it's been initialized. The whole point of resolve is that it runs before controller initialization so that you can inject and directly access the resolved items in your scope.

If you need to pass a variable to the next state you can do that by using the $stateParams object which is available for use in resolve. You can add data to it when changing states, eg:

In your template, if you have a objectId in your scope:

<a ui-sref="statename({'id': objectId})">Change states</a>

Or in your controller:

$scope.go('statename', {'id': $scope.objectId});

You can then retrieve that in your resolve by using the $stateParams:

resolve: {
    contactService: 'contactService',
    contacts: function ($stateParams, contactService) {
        return contactService.getContacts($stateParams.id);
    }
}

Upvotes: 21

Related Questions