Reputation: 12068
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 userTemplate
that 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
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