29

How to exchange data between components in Angular?

For instance, communicating between parent and child components or between siblings.

Graham John
  • 170
  • 12
吴桂林
  • 311
  • 1
  • 3
  • 3
  • Depends on what you want to do. Are you trying to trying to do rpc, message passing or just share variables? – John Siu Jun 27 '16 at 12:11

8 Answers8

19

If you are trying to communicate from a parent component to a child component, this is pretty clearly described using @Input and EventEmitters with @Output in the angular docs.

Angular 2 component interaction

As for communication across siblings, I posted an answer in a similar question that might help with the issue of sharing data across sibling components. Currently, i think the shared service method is the most efficient.

angular-2-sibling-component-communication

Community
  • 1
  • 1
Alex J
  • 3,085
  • 3
  • 19
  • 29
  • I found the answer useful and upvoted it, but then saw in the other page that its mainly relevant up to Angular 2: Alex J's answer is good but it no longer works with current Angular 4 as of July, 2017 – msanjay Oct 12 '17 at 06:55
19

Using a service:

import { Injectable } from '@angular/core';
import { Subject }    from 'rxjs/Subject';

@Injectable()
export class AppState {
  public _subject = new Subject<object>();
  public event = this._subject.asObservable();

  public publish(data: any) {
    this._subject.next(data);
  }
}

and you can publish event-like messages like this:

export class AppComponent {
  constructor(
    public appState: AppState
  ) {
    appState.publish({data: 'some data'});
  }
}

and you can subscribe to these events:

export class HomeComponent {
  constructor(
    public appState: AppState
  ) {
    appState.event.subscribe((data) => {
      console.log(data); // {data: 'some data'}
    });
  }
}
Evan Lévesque
  • 3,115
  • 7
  • 40
  • 61
  • If anyone looking for more generic approach based on share service and observable, can check out this article https://codewithlogic.wordpress.com/2020/04/18/communication-among-nested-components-in-angular/ – Arpit Apr 19 '20 at 16:04
12
  1. @Input and @Output

    If there are multipart components you can use @Input and @Output to exchange data. Document : https://angular.io/guide/component-interaction

    example: https://angular.io/generated/live-examples/component-interaction/eplnkr.html

  2. Dependency Injection

    you can store the data in Service, and then inject Service into the component which you want. such as "user.server.ts" in the example:

    https://angular.io/generated/live-examples/dependency-injection/eplnkr.html

Zilong Wang
  • 564
  • 4
  • 14
4

You will need to use dependency injection. Here is a small example: https://github.com/gdi2290/angular2do/blob/gh-pages/app/components/todo-item/todo-item.js

mhtsbt
  • 1,029
  • 2
  • 12
  • 26
1

using DataService stackbliz

sender.ts

import { Component } from '@angular/core';
import {dataService} from './dataservice.service';
@Component({
  selector: 'my-app',
  templateUrl: './app.component.html',
  styleUrls: [ './app.component.css' ]
})
export class AppComponent  {
  //name = 'Angular';
  constructor(private SVC: dataService ){

  }
  sender(){
    this.SVC.name="sender"
    console.log("sending this string:    "+this.SVC.name)
  }

}

dataservice.ts

   import { Injectable } from '@angular/core';

    @Injectable()
    export class dataService {
    name=""
      constructor() { }
    }

receiver.ts

import { Component, OnInit } from '@angular/core';
import {dataService} from '../dataservice.service';
@Component({
  selector: 'app-recieved',
  templateUrl: './recieved.component.html',
  styleUrls: ['./recieved.component.css']
})
export class RecievedComponent implements OnInit {
  constructor(private dataservice: dataService ){

  }
  ngOnInit() { 
  }
print(){
  console.log("recieved:    " +this.dataservice.name)
}
}
Shafeeq Mohammed
  • 1,193
  • 17
  • 25
1

By using any of the following methods we can connect 2 components.

  1. using @input()
  2. using @output()
  3. using services.
  4. parent component calling viewchild.
  5. parent interacting with child using a local variable.
gaya3_96
  • 19
  • 1
0

There is Events API in angular which can do it for you.

Click here for more details on Events.

Below is a quick example I am currently using in my project. Hope it helps someone in need.

import { Events } from 'ionic-angular';

Usage :

  constructor(public events: Events) {
        /*=========================================================
        =  Keep this block in any component you want to receive event response to            =
        ==========================================================*/
        // Event Handlers
        events.subscribe('menu:opened', () => {
            // your action here
            console.log('menu:opened');
        });
        events.subscribe('menu:closed', () => {
            // your action here
            console.log('menu:closed');
        });
    }

    /*=====================================================
    = Call these on respective events - I used them for Menu open/Close          =
    ======================================================*/

    menuClosed() {
        // Event Invoke
        this.events.publish('menu:closed', '');
    }
    menuOpened() {
        // Event Invoke
        this.events.publish('menu:opened', '');
    }

  }
Sangwin Gawande
  • 7,658
  • 8
  • 48
  • 66
-1

Inter component communication can be achieved in AngularJS. In AngularJS we have something called as require property which needs to be mapped in the component. Follow the example below which will access the function addPane(parameter) of the component myTabs from the component myPane: -

Project structure:

HTML

  1. index.html
  2. my-tabs.html
  3. my-pane.html

JS

  1. script.js

script.js

angular.module('docsTabsExample', [])
    .component('myTabs', {
      transclude: true,
      controller: function MyTabsController() {
        var panes = this.panes = [];
        this.select = function(pane) {
          angular.forEach(panes, function(pane) {
            pane.selected = false;
          });
          pane.selected = true;
        };
        this.addPane = function(pane) {
          if (panes.length === 0) {
            this.select(pane);
          }
          panes.push(pane);
        };
      },
      templateUrl: 'my-tabs.html'
    })
    .component('myPane', {
      transclude: true,
      require: {          //This property will be used to map other component
        tabsCtrl: '^myTabs' // Add ^ symbol before the component name which you want to map.
      },
      bindings: {
        title: '@'
      },
      controller: function() {
        this.$onInit = function() {
          this.tabsCtrl.addPane(this);  //Calling the function addPane from other component.
          console.log(this);
        };
      },
      templateUrl: 'my-pane.html'
    });

index.html

<my-tabs>
  <my-pane title="Hello">
    <h4>Hello</h4>
    <p>Lorem ipsum dolor sit amet</p>
  </my-pane>
  <my-pane title="World">
    <h4>World</h4>
    <em>Mauris elementum elementum enim at suscipit.</em>
    <p><a href ng-click="i = i + 1">counter: {{i || 0}}</a></p>
  </my-pane>
</my-tabs>

my-tabs.html

<div class="tabbable">
  <ul class="nav nav-tabs">
    <li ng-repeat="pane in $ctrl.panes" ng-class="{active:pane.selected}">
      <a href="" ng-click="$ctrl.select(pane)">{{pane.title}}</a>
    </li>
  </ul>
  <div class="tab-content" ng-transclude></div>
</div>

my-pane.html

<div class="tab-pane" ng-show="$ctrl.selected" ng-transclude></div>

Code snippet : https://plnkr.co/edit/diQjxq7D0xXTqPunBWVE?p=preview

Reference: https://docs.angularjs.org/guide/component#intercomponent-communication

Hope this helps :)