8

I have implemented a single page application with AngularJS. The page consists of a content area in the middle and sections assembled around the center that show additional info and provide means to manipulate the center.

enter image description here

Each section (called Side Info) and the content area have a separate AngularJS controller assigned to them. Currently, I communicate via $rootScope.$broadcast and $scope.$on(), e.g.

app.controller('PropertiesController', function ($scope, $rootScope) {

    $scope.$on('somethingHappened', function(event, data){
        // react
    });

});

I then call to communicate with other controllers:

$rootScope.$broadcast('somethingHappened', data);

I have quite a lot of communication happening between the Controllers. Especially if something is going on in the content area, several side info elements have to adopt. The other way around is also frequent: a user submits a form (located in a side info) and the content area and other side info elements have to adopt.

My question: Is there a better way to handle SPA with heavy controller communication?

The code works fine but it is already getting a bit messy (e.g. it is hard to find which events are handled where etc.). Since the application is likely to grow a lot in the next weeks, I'd like to make those changes (if there are any better solutions) asap.

WeSt
  • 2,628
  • 5
  • 22
  • 37
  • I'm doing my first Angular project that consist in create a onepage APP. i'm creating templates inside templates and i handled all scopes from directives into an array. Then i can catch and modify those. don't know if thats a good way or if it can help you. – nada Feb 05 '15 at 15:40
  • 5
    Using a shared service is another way to communicate – New Dev Feb 05 '15 at 15:42
  • Often, you can put shared things into up-level PagesController. So you can easily access to them through scope. Sometimes, you can add some service that will share state variables. – dubadub Feb 05 '15 at 15:43
  • 1
    Is there a reason why you aren't using services? I rarely use, and try to avoid broadcast/emit. – Dieterg Feb 05 '15 at 15:44
  • @DieterGoetelen I thought of using services as well but each controller would basically need all services then. Maybe that's still a better solution than using `broadcast` and `on` though. – WeSt Feb 05 '15 at 15:46
  • @WeSt, not *all services*, but just the services each controller needs. – New Dev Feb 05 '15 at 15:53
  • This video could be helpful https://egghead.io/lessons/angularjs-sharing-data-between-controllers – Max Brodin Feb 05 '15 at 15:58
  • Are you actually *seeing* a performance problem? Or is your real issue the *organization* of the communication (what is wired to what etc.)? – Davin Tryon Feb 05 '15 at 16:22
  • @DavinTryon there is no performance problem here. It's just about the structure. I have around 10 different event types currently. This number might grow considerably in the next weeks. It's already not easy to spot on which parts a single event has impact, so I want to restructure it (for my own future's sanity and those of my co-workers ;) ). – WeSt Feb 05 '15 at 16:37
  • `not easy to spot on which parts a single event`. This is also could be seen as *advantage*. You are decoupling the event from the handling of the event. A naming convention for the events could help (like pllacing events in a structure (like a `constant` file)). – Davin Tryon Feb 05 '15 at 16:48

4 Answers4

1

This is really interesting. Pub/Sub should be a right solution here.

You could add extra order to your project by using Angular services as your MVC's model, and update this model for each change. The issue here is that you should implement an observable pattern inside your service and register to them, in order for this to be live synced. So - we're back to Pub/Sub (or other Observable solution that you could think about...).

But, the project will be better organised that way.

For example - SideInfo1Service will be a service/model. Each property change will trigger an observable change which will change all listeners:

myApp.factory('SideInfo1Service', function($scope){
    var _prop1; 
    return {
       setProp1: function(value){
           $scope.$broadcast('prop1Changed', value);
           _prop1 = value;       
       },
       getProp1: function(){
           return _prop1;
       }
    }
});

You could find those really interesting blog posts about using Angular Services as your MVC's model:

http://toddmotto.com/rethinking-angular-js-controllers/

http://jonathancreamer.com/the-state-of-angularjs-controllers/

And, this post is about observable pattern in Angularjs:

https://stackoverflow.com/a/25613550/916450

Hope this could be helpful (:

Community
  • 1
  • 1
Yaniv Efraim
  • 6,633
  • 7
  • 53
  • 96
0

You can use

$rootScope.$emit('some:event') ;

because it goes upwards and rootscope ist the top level

use

var myListener = $rootScope.$on('some:event', function (event, data) { });
$scope.$on('$destroy', myListener); 

to catch the event

Then you have a communication on the same level the rootscope without bubbling

Here is my implemented eventbus service

http://jsfiddle.net/navqtaoj/2/

Edit: you can use a namespace like some:event to group and organize your event names better and add log outputs when the event is fired and when the event is catch so that you easy can figure out if fireing or catching the wrong eventname.

micha
  • 1,238
  • 10
  • 7
0

You have multiple options in order to avoid broadcasts calls:

  1. Share data between controllers using services like it was mentioned in the comments. You can see how to this at: https://thinkster.io/egghead/sharing-data-between-controllers

  2. Create a main controller for the whole page and child controllers for each section (Content Area and Side Info). Use scope prototype inheritance. For example:

if in main controller you have: $scope.myObject = someValue;

in child Controllers you can set: $scope.myObject.myProperty = someOtherValue;

you can access myObject.myProperty from your Main Controller

rave
  • 1,022
  • 1
  • 12
  • 23
  • for scope inheritance is important to not use variables on the scope directly better register your variables in an object on scope so that you have a dot in your model name http://stackoverflow.com/questions/14049480/what-are-the-nuances-of-scope-prototypal-prototypical-inheritance-in-angularjs/14049482#14049482 – micha Feb 05 '15 at 16:13
0

Very important question and very good answers.

I got inspired and created three plunks showing each technique:

Check out the plunks, hope this helps.

463035818_is_not_an_ai
  • 109,796
  • 11
  • 89
  • 185
wojjas
  • 1,046
  • 1
  • 9
  • 21