alonisser
alonisser

Reputation: 12068

Angular - resolving for multiple controllers in the same view/route/page

We are building a big SPA , currently the app is build with widgets/components. each with a template, controller. but many can be nested in the same route. for example: In the route /users/ I can have a `userCtrl and a userTemplatethat renders the user stats parts. a graphCtrl and a graphTemplate to render some d3 graphs. a listCtrl and a listTemplate to render a list. all of those widgets should be reusable (with different css and layouts, sometimes with the same ctrl different templates in other pages). I need to instantiate some data from a service - Lets say a service that return my user id and more validations. so in the main app routing i define a resolve{myId: function(srvname){return srvname.myId}} for userCtrl route which the when clause of routeProvider routes to.

My problem is that listCtrl doesn't wait for userCtrl (the main page ctrl , which gets the route) to resolve the different promises, and then fails with missing data.

Is there a way to define the same resolve for multiple controllers, that some of them aren't a direct route target but more of (very) big component? Is there a better/smarter way to do this?

I know I can use directive for that. but moving the bussiness logic from listCtrl to a directive looks plain wrong.

I'll be glad for any help and advice

Upvotes: 1

Views: 1522

Answers (1)

David Pope
David Pope

Reputation: 6587

The standard advice for communicating between controllers is to use a service. If I'm reading your description right, then in your case the top-level controller would be responsible for setting up the model and setting it in the service for the "descendant" controllers to read.

Edit for @alonisser's comment:

You should be able to data-bind the dependent controller's view to a function on the dependent $scope (say viewData() in such a way that if the function returns null, the element is hidden or shows a "spinner" UI.

The dependent template would look something like:

...
<div data-ng-if="viewData() !== null">
    <!-- show display elements based on the return value from viewData() -->
</div>
...

The setup for viewData would look something like this:

...
$scope.viewData = function() {
    if ($scope.model.asyncData === null) {
        $log.info("no data yet!");
        return null;
    }
    else
        return prepare_for_view($scope.model.asyncData);
}
...

And the async calls in the userCtrl look something like:

something_that_returns_a_promise.then(function (result) {
    $scope.model.asyncData = result;
});

A key piece is that the something_that_returns_a_promise() has to be something "inside" the AngularJS call stack, for example done using $http. When that's the case, Angular automatically calls $scope.$apply(), and your dependent display elements should update seamlessly. Otherwise you will need to call $scope.$apply() yourself in the async callback that sets $scope.model.asyncData.

Upvotes: 1

Related Questions