3

I'm working on a small app in AngularJS. My project contain a Body.html file that contain 3 views: SideMenu, Header and Content, each with each own Controller and a MainController as there parent - the controller of the Body.html.
Can the header's controller change a property in the side-menu - the open/close status of the side-menu. And Can the side-menu controller change a property in the header - the header's text.
I can use the main controller, since both of the header's controller and the side-menu controller can reference the main controller. But the data won't be consist. Updating the data from the 1st controller wan't effect the data in the 2nd controller (without the use of $watch).

Can both the side-menu's controller and the header's controller (sibling controllers) communicate with each other? without the help of there parent?


Body.html

 <div>
     <!-- Header placeholder -->
     <div ui-view="header"></div>

     <!-- SideMenu placeholder -->
     <div ui-view="sideMenu"></div>

     <!-- Content placeholder -->
     <div ui-view></div>
 </div>

Header.html

 <div>
    {{ headerCtrl.text }}
 </div>
 <div ng-click="headerCtrl.openSideMenu()">
    --Open--
 </div>

HeaderController.js

 // sideMenuCtrl = ???
 headerCtrl.text = "Title";
 headerCtrl.openSideMenu = function()
 {
    sideMenuCtrl.isSideMenuOpen = true;
 };

SideMenu.html

 <div ng-class={ 'side-menu-open': sideMenuCtrl.isSideMenuOpen }>

     <div ng-repeat="menuItem in sideMenuCtrl.sideMenuItems"
          ng-click="sideMenuCtrl.selectMenuItem(menuItem)">
          {{ menuItem.text }}
     </div>
 </div>

SideMenuController.js

 // headerCtrl = ???
 sideMenuCtrl.selectMenuItem = function(menuItem)
 {
    headerCtrl.text = menuItem.text;
 }
Gil Epshtain
  • 8,670
  • 7
  • 63
  • 89
  • You might want to use a service or factory to share data and logic between controllers. See angular documentation and guide about [service](https://docs.angularjs.org/guide/services) and [factory](https://docs.angularjs.org/guide/providers) – zoom Feb 22 '16 at 22:45
  • redux/flux is a good pattern for top-down data flow to all siblings and descendants. or, more generically, EventEmitters, or DOM events on an existing parent (events bubble up). a global variable (the horror) can work simplistic wonders in smaller apps. – dandavis Feb 22 '16 at 22:46
  • A can use services/factories to share data between controllers. But I would have the same issue as using the parent scope - the data wan't be consist. I would need to use $watch and listen to data change in each controller. Can I do this without $watch? – Gil Epshtain Feb 22 '16 at 22:52
  • See my answer, where $watch is not used. – zoom Feb 22 '16 at 23:50

1 Answers1

4

As stated in my comment, you can use an AngularJS service to share some data between your controllers.

app.service('AppContextService', function(){
    this.context = {
        isSideMenuOpen: false
    };
});

app.controller('SideMenuCtrl', ['$scope', 'AppContextService', function($scope, AppContextService) {
    // exposing the application context object to the controller.
    $scope.appContext = AppContextService.context;
}]);

app.controller('HeaderCtrl', ['$scope', 'AppContextService', function($scope, AppContextService) {
    $scope.appContext = AppContextService.context;
    $scope.openSideMenu = function()
    {
        $scope.appContext.isSideMenuOpen = true;
     };
}]);

Then adapt the HTML to use your shared appContext object.

<div ng-class={ 'side-menu-open': appContext.isSideMenuOpen }>
   [...]
</div>

Here is a working fiddle that illustrates the issue: fiddle

This answer covers the use of a service to fit your needs but I am sure that there are other (and perhaps better) ways to tackle the problem which might involve other Angular feature, or even some overall application refactoring.

To dig a little deeper, this SO topic might be a good start: difference between service, factory and providers

Community
  • 1
  • 1
zoom
  • 1,686
  • 2
  • 16
  • 27