简体   繁体   中英

Communication between spread out AngularJS components

We have various components in the application that are not in parent/child or sibling relationships. Let's say a checkbox that when in checked state is supposed to change the state of another component which is in a completely different container.

The application is over 500 different views, so a controller for each one is not an option. Those interactions are also completely custom, so we would need tens of methods to cover all of them (checkbox to tab, multiple checkboxes to tab, multiple checkboxes to more checkboxes etc).

What is the best course of action here? So far we thought about a globally available service to register components by id and then subscribe the dependent components to listen for the status change on that particular id in the service (for example in an ng-if directive to toggle), or use Redux. We have no previous experience with complex relationships like that.

Any ideas or similar experiences would be greatly appreciated.

The Observer pattern as you describe it is being implemented in angularjs with event emmiters ( $broadcast $emit ) so there is no need to create an independent service.

The point of component based applications is to have some tree structured architecture. So in those cases the child component notifies the parent and then the parent notifies some other child maybe and goes on.

If your application is not structured like this you might consider a refactoring but for now you could just bind some event emitters.

To solve this issue use the publish/subscribe pattern that allow get a loosely-coupled architecture .

On an AngularJS application a great library is postaljs that allow implements this pattern easely:

Define at app.config a $bus $scope variable that will be accesible on all places of the application: controlers, directives, ...

app.config(function($provide) {
    $provide.decorator('$rootScope', [
        '$delegate',
        function($delegate) {
            Object.defineProperty($delegate.constructor.prototype,
                '$bus', {
                    get: function() {
                        var self = this;
                        return {
                            subscribe: function() {
                                var sub = postal.subscribe.apply(postal, arguments);
                                self.$on('$destroy',
                                    function() {
                                        sub.unsubscribe();
                                    });
                            },
                            channel: function() {
                                return postal.channel.apply(postal, arguments);
                            },
                            publish: function() { postal.publish.apply(postal, arguments); }
                        };
                    },
                    enumerable: false
                });
            return $delegate;
        }
    ]);
});

Publish
Publish on item updated.

var channel = $scope.$bus.channel('myresources');
channel.publish("item.updated", data);

Publish on list updated

var channel = $scope.$bus.channel('myresources');
....
channel.publish("list.updated", list);

Subscribe The controller/directive that needs be notified for an event on the "myresources" channel.

 var channel = $scope.$bus.channel("myresources");
 ....
 //The wildcard * allow be notified on item/list. updated
 channel.subscribe("*.updated", function(data, envelopment) {
   doOnUpdated(); 
 });

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM