0

Hey I have the following component tree: I have a root component called rules and two sons components called: rulesPanel & rulesEditor.

Now I can create a communication between son and mother component:

rulesEditor can call to rules component and jump an event on him.

rulesPanel can call to rules component and jump an event on him.

I want to have a communication between the 2 brothers:

rulesEditor and rulesPanel.

I don't want to use $scope or $broadcast, I want to do it through the bindings of the component himself. I have tried to think of way of doing so, but all I got is that I can call to upper level but not to a parallel level.

Edit: My Question is different from the possible duplication, I don't want to pass a data, I want to execute a function in one component and then execute another function in the sibling component as a result of a click function in the brother component.

Here is my code and what I have achieved so far:

var app = angular.module("app",[]);

angular.module('app').component('rules', {
  template: `
            <rules-panel dial-mom="$ctrl.receivePhoneCall(message)">
            </rules-panel>
            <rules-editor>
            </rules-editor>`,
  bindings: {
  },
  controller: rulesController,
});

function rulesController(){
  var self = this;
  self.receivePhoneCall = function(message){
    console.log("Hello Son");
    console.log("I got your message:",message)
  }
  console.log("rulesController")
}

angular.module('app').component('rulesPanel', {
  template: `<h1>rulesPanel</h1>
              <button ng-click="$ctrl.callMom()">CallMom</button>
     <button ng-click="$ctrl.CallBrother()">CallBrother</button>`,
  bindings: {
    dialMom: '&'
  },
  controller: rulesPanelController,
});

function rulesPanelController(){
  var self = this;
  console.log("rulesPanelController");
  self.callMom = function(){
    console.log("Call mom");
    self.dialMom({message:"Love you mom"});
  }
  
   self.CallBrother = function(){
    console.log("Call brother");
  }
}

angular.module('app').component('rulesEditor', {
  template: '<h1>rulesEditor</h1>',
  bindings: {
  },
  controller: rulesEditorController,
});

function rulesEditorController(){
  console.log("rulesEditorController")
}
<script src="https://cdnjs.cloudflare.com/ajax/libs/angular.js/1.6.1/angular.min.js"></script>
<div ng-app="app">
  
  <rules></rules>
  
</div>
Brk
  • 1,247
  • 2
  • 23
  • 55
  • This can be done through parent component or through common service. It depends on particular case which way is better. If there's only one 'rules', the service should be good. – Estus Flask Feb 27 '17 at 20:45
  • I have a parent component called rules, I don't need a service for this. Can you give me an example of how a click event occur in son component can trigger an event on brother component? Thanks for the help. – Brk Feb 27 '17 at 20:54
  • In general in MV* frameworks events aren't communicated sideways or down. Events are communicated upward; model values are communicated downward. Having state changes in more than one place violates the [Single Source of Truth](https://en.wikipedia.org/wiki/Single_source_of_truth) principle. – georgeawg Feb 27 '17 at 21:21
  • Possible duplicate of [How to pass data between sibling components without using $scope?](http://stackoverflow.com/questions/36033940/how-to-pass-data-between-sibling-components-without-using-scope) – georgeawg Feb 27 '17 at 21:32
  • my mistake this is realy a duplication – Brk Feb 27 '17 at 22:46

1 Answers1

2

You can use a semi Angular 2 component approach. Meaning you can use Input/output approach to achieve this.

I will give you an example and you can take it from there.

Let's say you have a header and a main component.

In your header component where you want to notify the main you can raise an event like this:

.component('headerComponent', {
  template: `
    <h3>Header component</h3>
    <a ng-class="{'btn-primary': $ctrl.view === 'list'}" ng-click="$ctrl.setView('list')">List</a>
    <a ng-class="{'btn-primary': $ctrl.view === 'table'}" ng-click="$ctrl.setView('table')">Table</a>
  `,
  controller: function() {
    this.setView = function(view) {
      this.view = view
      this.onViewChange({$event: {view: view}})
    }
  },
  bindings: {
    view: '<',
    onViewChange: '&'
  }
})

With binding view: '<' we specify that header component will be able to read outer something and bind it as view property of the own controller.

Header controller can be used like this:

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

On the other hand main in simpler, it only needs to define input it accepts:

.component('mainComponent', {
  template: `
    <h4>Main component</h4>
    Main view: {{ $ctrl.view }}
  `,
  bindings: {
    view: '<'
  }
})

And finally it all wired together:

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

Here is a plunker.

Yaser
  • 5,609
  • 1
  • 15
  • 27
  • thanks for the quick reply, But this planker doesn't answer my question I don't want to pass a data, I want to execute a function in one component and then execute another function in the sibling component as a result of a click function in the brother component. – Brk Feb 27 '17 at 21:44