WeSt
WeSt

Reputation: 2684

Heavy controller communication in AngularJS

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.

Upvotes: 8

Views: 386

Answers (4)

wojjas
wojjas

Reputation: 1096

Very important question and very good answers.

I got inspired and created three plunks showing each technique:

Check out the plunks, hope this helps.

Upvotes: 0

Yaniv Efraim
Yaniv Efraim

Reputation: 6713

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 (:

Upvotes: 1

micha
micha

Reputation: 1238

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.

Upvotes: 0

rave
rave

Reputation: 1032

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

Upvotes: 0

Related Questions