How to pass object from one component to another in Angular 2?

AngularAngular2 Directives

Angular Problem Overview


I have Angular components and first component uses the second one as a directive. They should share the same model object, which is initialized in the first component. How can I pass that model to the second component?

Angular Solutions


Solution 1 - Angular

For one-way data binding from parent to child, use the @Input decorator (as recommended by the style guide) to specify an input property on the child component

@Input() model: any;   // instead of any, specify your type

and use template property binding in the parent template

<child [model]="parentModel"></child>

Since you are passing an object (a JavaScript reference type) any changes you make to object properties in the parent or the child component will be reflected in the other component, since both components have a reference to the same object. I show this in the Plunker.

If you reassign the object in the parent component

this.model = someNewModel;

Angular will propagate the new object reference to the child component (automatically, as part of change detection).

The only thing you shouldn't do is reassign the object in the child component. If you do this, the parent will still reference the original object. (If you do need two-way data binding, see https://stackoverflow.com/a/34616530/215945).

@Component({
  selector: 'child',
  template: `<h3>child</h3> 
    <div>{{model.prop1}}</div>
    <button (click)="updateModel()">update model</button>`
})
class Child {
  @Input() model: any;   // instead of any, specify your type
  updateModel() {
    this.model.prop1 += ' child';
  }
}

@Component({
  selector: 'my-app',
  directives: [Child],
  template: `
    <h3>Parent</h3>
    <div>{{parentModel.prop1}}</div>
    <button (click)="updateModel()">update model</button>
    <child [model]="parentModel"></child>`
})
export class AppComponent {
  parentModel = { prop1: '1st prop', prop2: '2nd prop' };
  constructor() {}
  updateModel() { this.parentModel.prop1 += ' parent'; }
}

Plunker - Angular RC.2

Solution 2 - Angular

Component 2, the directive component can define a input property (@input annotation in Typescript). And Component 1 can pass that property to the directive component from template.

See this SO answer https://stackoverflow.com/questions/33966692/how-to-do-inter-communication-between-a-master-and-detail-component-in-angular2/33967426#33967426

and how input is being passed to child components. In your case it is directive.

Solution 3 - Angular

you could also store your data in an service with an setter and get it over a getter

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

@Injectable()
export class StorageService {

    public scope: Array<any> | boolean = false;

    constructor() {
    }

    public getScope(): Array<any> | boolean {
        return this.scope;
    }

    public setScope(scope: any): void {
        this.scope = scope;
    }
}

Solution 4 - Angular

From component

import { Component, OnInit, ViewChild} from '@angular/core';
    import { HttpClient } from '@angular/common/http';
    import { dataService } from "src/app/service/data.service";
    @Component( {
        selector: 'app-sideWidget',
        templateUrl: './sideWidget.html',
        styleUrls: ['./linked-widget.component.css']
    } )
    export class sideWidget{
    TableColumnNames: object[];
    SelectedtableName: string = "patient";
    constructor( private LWTableColumnNames: dataService ) { 
       
    }
    
    ngOnInit() {
        this.http.post( 'getColumns', this.SelectedtableName )
            .subscribe(
            ( data: object[] ) => {
                this.TableColumnNames = data;
     this.LWTableColumnNames.refLWTableColumnNames = this.TableColumnNames; //this line of code will pass the value through data service
            } );
    
    }    
    }

DataService

import { Injectable } from '@angular/core';
import { BehaviorSubject, Observable } from 'rxjs';

@Injectable()
export class dataService {
    refLWTableColumnNames: object;//creating an object for the data
}

To Component

import { Component, OnInit } from '@angular/core';
import { dataService } from "src/app/service/data.service";

@Component( {
    selector: 'app-linked-widget',
    templateUrl: './linked-widget.component.html',
    styleUrls: ['./linked-widget.component.css']
} )
export class LinkedWidgetComponent implements OnInit {

    constructor(private LWTableColumnNames: dataService) { }

    ngOnInit() {
    console.log(this.LWTableColumnNames.refLWTableColumnNames);
    }
    createTable(){
        console.log(this.LWTableColumnNames.refLWTableColumnNames);// calling the object from another component
    }

}

Solution 5 - Angular

Use the output annotation

@Directive({
  selector: 'interval-dir',
})
class IntervalDir {
  @Output() everySecond = new EventEmitter();
  @Output('everyFiveSeconds') five5Secs = new EventEmitter();
  constructor() {
    setInterval(() => this.everySecond.emit("event"), 1000);
    setInterval(() => this.five5Secs.emit("event"), 5000);
  }
}
@Component({
  selector: 'app',
  template: `
    <interval-dir (everySecond)="everySecond()" (everyFiveSeconds)="everyFiveSeconds()">
    </interval-dir>
  `,
  directives: [IntervalDir]
})
class App {
  everySecond() { console.log('second'); }
  everyFiveSeconds() { console.log('five seconds'); }
}
bootstrap(App);

Attributions

All content for this solution is sourced from the original question on Stackoverflow.

The content on this page is licensed under the Attribution-ShareAlike 4.0 International (CC BY-SA 4.0) license.

Content TypeOriginal AuthorOriginal Content on Stackoverflow
QuestionAnoush HakobyanView Question on Stackoverflow
Solution 1 - AngularMark RajcokView Answer on Stackoverflow
Solution 2 - AngularChandermaniView Answer on Stackoverflow
Solution 3 - AngularuemanView Answer on Stackoverflow
Solution 4 - AngularShafeeq MohammedView Answer on Stackoverflow
Solution 5 - AngularE. FortesView Answer on Stackoverflow