Seven Lee Seven Lee - 1 month ago 15
AngularJS Question

Efficient way to communicate components or directives in Angular 1.x

According to the below image:



enter image description here

I want to improve components communication method....I think this way is not efficient.

When clicking tabsetComponent to emit event, then parent controller catch this event, changing rootScope variable. Using $watch rootScope variable in tableComponent to trigger http fetch data function...

Could anyone has better and efficient way to communicate sibling component?

Answer

The accepted AngularJS method for communication between components is using component attributes for communication.

<div ng-controller="rootCtrl as vm">

    <tab-set-component tsc-click="vm.fn($event, data)">
    </tab-set-component>

    <table-component="vm.tableData">
    </table-component>

</div>

For more information on defining component attributes, see AngularJS Comprehensive Directive API -- isolate scope

Best practices

Only use .$broadcast(), .$emit() and .$on() for atomic events

Events that are relevant globally across the entire app (such as a user authenticating or the app closing). If you want events specific to modules, services or widgets you should consider Services, Directive Controllers, or 3rd Party Libs

  • $scope.$watch() should replace the need for events
  • Injecting services and calling methods directly is also useful for direct communication
  • Directives are able to directly communicate with each other through directive-controllers

-- AngularJS Wiki Best Practices


Controller Example

In your html, you use vm.fn that came from root controller right? So your advice is it should call the click method defined root controller, the click method will trigger http request function defined on the rootScope, then get table component datas, then bind the datas on table component attribute.

As example:

angular.module("myApp", []);

angular.module("myApp").controller("rootCtrl", function($http) {
    var vm = this;

    vm.tableData = { /* initial data */ };

    //click handler
    vm.fn = function(event, url) {
        $http.get(url).then (function onFulfilled(response) {
            vm.tableData = response.data;
        }).catch (function onRejected(response) {
            console.log(response.status);
        });
    };
});

The above example avoids cluttering $rootScope. All the business logic and data is contained in the controller.

The controller sets the initial data for the table-component, receives click events from the tab-set-component, makes HTTP requests, handles errors, and updates the data to the table-component.


UPDATE -- Using Expression Binding

Another approach is using expression binding to communicate events:

<header-component view="root.view" on-view-change="root.view = $event.view">
</header-component>

<main-component view="root.view"></main-component>

For more information, see SO: How to pass data between sibling components in angular 1.5 , not using $scope