Reputation: 13753
The question might seem too vague but I could not think of a better way to describe the idea, so I'll try to explain it in details.
I have MasterController attached to <html>
tag of my SPA application. This MasterController contains all the logic and models for controlling the following UI elements:
<title>
tag)Show filters
, Export data to Excel
and Add new record
.While the first two items on this list can be managed through detection of current ui-router state (through its $stateChangeSuccess
event), the last two (username and buttons) are somewhat problematic, especially the buttons.
I can manage the button actions using $broadcast
, so every controller can be notified about clicks on any button. But the tricky part here is that the buttons might be needed in different combinations - one page might need all of them, and another one might need none.
Let's say, ui-router loads some CustomersController. At that point MasterController receives $stateChangeSuccess
event and by default hides all the buttons.
But now, how does CustomersController tell to MasterController that CustomersController will need two specific buttons from the very beginning?
Theoretically, I could use $emit
from CustomersController to send an event to MasterController, but it somehow feels ugly. Events are meant for, well, events and not for sending requests like "hey, MasterController, if you are somewhere up the scope, can you please show the following buttons?".
Of course, I might be wrong and maybe there is some way to use Angular event system to manage this scenario in clean way.
What came to my mind is that maybe in the $stateChangeSuccess
event I could somehow detect if there are currently any listeners for my button click events and then I could hide buttons which do not have any listeners attached, but I'm not sure how to do it, and I'm not sure whether it will work as expected - whether old listeners will be detached when ui-router recreates the view with another controller.
Upvotes: 1
Views: 72
Reputation: 13753
Today I got a tricky idea based on @Diego Castaño Chillarón 's answer. I thought - but is it possible to use ui-router to swap controller of existing view and will it rebind also the $scope? And will I still be able to replace inner parts of the loaded view?
It turned out that it is doable! Now I don't have to control the common view fragments from the master control, and I don't need also to inherit or duplicate them - I just switch the controller to the required one through ui-router.
Like this:
$stateProvider
.state("customers", {
url: "^/customers",
views: {
"controller": {
controller: "CustomerController as cntrlr"
},
"page@customers": // <- this is important, absolute name required for ui-router to find nested view
{
templateUrl: "customers"
}
}
}) // other routes follow in the same manner
And my HTML looks like this:
<div id="routes-root" ui-view="controller">
<div id="content-header-buttons">
<button type="button" ng-click="master.toggleFilter()">Filter data</button>
<button type="button" ng-click="cntrlr.exportClicked()">Export</button>
<button type="button" ng-click="cntrlr.createNewClicked()">Create</button>
</div>
<div id="view-content" ui-view="page"></div>
</div>
As you see, I left master controller to control only visibility for filters block, which won't change.
But controller itself is attached to #routes-root
element, preserving inner content, and ui-router (or Angular) is smart enough to attach $scope and cntrlr
variable to the loaded controller. And then I load inner view into #view-content
, which also gets attached to the already loaded controller.
Upvotes: 0
Reputation: 447
If you are just nesting controllers, their corresponding scopes actually make use of prototypical inheritance. So you could just define a function $scope.configureButtons
in your MasterController and call this function from the $scope
in your nested CustomerController.
If Controllers are not nested you would probably need to resort to $rootScope.$broadcast
for setting up your buttons.
Upvotes: 1
Reputation: 148
Why not just simply using diferent controllers for each view? Maybe generalize a bit the CustomerController and extend it (specialize it) for every combination of buttons you need. Using the $stateChangeSuccess feels like avoiding polymorphism to me.
Upvotes: 0