2

For the past few days we have been writing a new angular.js based front-end for our REST-service. So far things are moving along nicely and we have built lots of small pages and components.

We are now starting to integrate these things into a complete application and are wondering how to handle the main view based on two different menu's.

We would like to have all these three components change based on some global state. Ideally controlled by the $routeProvider based on the url.

We can think of several ways to do this. However none of them seem right and we have found no clear documentation on how the developers of angular envisioned this being done.

Some reduced snippets:

index.html

<!DOCTYPE html>
<html data-ng-app="myapp">
<head>
    ....snip...
</head>
<body>
    <div id="system-menu" data-ng-controller="MenuCtrl" data-ng-include="'partials/menu/system.html'"></div>
    <div id="main">
        <div id="main-menu" data-ng-controller="MenuCtrl" data-ng-include="'partials/menu/main.html'"></div>
        <div id="content" data-ng-view></div>
    </div>
</body>

app.js

var myapp = angular.module('myapp', ['ngResource', 'ui']).
    config(['$routeProvider', function($routeProvider) {
        $routeProvider.
            when('/messages', {
                templateUrl: 'partials/messages.html',
                controller: MessagesCtrl
            }).
            when('/messages/:messageId', {
                templateUrl: 'partials/messages.html',
                controller: MessagesCtrl
            }).
            ...snip...
            otherwise({
                redirectTo: '/messages'
        });
    }]);

When the user clicks a link to /messages/1 i want the controller messagesCtrl to be used for the view. This is easy and works as posted above. However my MenuCtrl does not "notice" this happening, and manually broadcasting a message to let it know of the page change so it can show the sub-menu seems ugly to me. Because the only reason for this message would be to update the menu causing some unwanted knowledge of the other controller.

So far we like the documentation on angular.js but it seems to be lacking in the big-picture department.

Can anyone provide us with a link or some pointers on the idiomatic way to do this?

Kenneth Lynne
  • 15,461
  • 12
  • 63
  • 79
martijnve
  • 993
  • 2
  • 9
  • 23

3 Answers3

4

In order to get your menu highlighting working you could setup a simple method within your menu controller which reads out the current route from the the $location provider.(Quickly mocked)

// Within your controller.
$scope.isActiveUrl = function (route) {
    return route === $location.path()
}
// 
Within the view
ng-class="{ 'active' : isActiveUrl('your/path') }"

Also see: How to highlight a current menu item?

Community
  • 1
  • 1
ngr
  • 139
  • 2
  • 10
3

We would like to have all these three components change based on some global state. Ideally controlled by the routeprovider based on the url.

To communicate between controllers, you can create a service, which can broadcast the changes to all its subscribers.

Checkout the following youtube video and jsfiddles links in the video

http://www.youtube.com/watch?v=1OALSkJGsRw

venkat
  • 2,310
  • 1
  • 15
  • 15
  • This does explain the inter controller communication quite nicely, thanks. However it does not solve my problem in a clean way. Let me try to be more specific: When the user clicks a link to /messages/1 i want the controller messagesCtrl to be used for the view. This is easy and works as posted above. However my MenuCtrl does not "notice" this happening and manually broadcasting a message to let it know of the page change so it can show the sub-menu seems ugly to me. Because the only reason for this message would be to update the menu causing some unwanted knowledge of the other controller. – martijnve Nov 19 '12 at 09:17
0

Venkat is right - use a service. You need to set a watch in MenuCtrl on the thing that's changing in order for it to notice the change. That thing can be a property of a service that you expose or a return value of a function in the service.

When the user clicks on the link and you are in the first controller, set something in the service that indicates a menu state. That element is what you will want to put a watch on in your secondary controller. Then, when that changes, the cascading effect is that an action in the secondary controller will fire and you can do whatever you want with the value you just set.

Obviously, you need to inject these services into both your controllers.

BoxerBucks
  • 3,124
  • 2
  • 21
  • 26