Как передать объект из одного компонента в другой в Angular 2?

У меня есть компоненты Angular, и первый компонент использует второй как директиву. Они должны использовать один и тот же объект модели, который инициализируется в первом компоненте. Как я могу передать эту модель второму компоненту?


person Anoush Hakobyan    schedule 04.12.2015    source источник
comment
Можете ли вы опубликовать код? Как правило, вы используете локальные переменные шаблона для такого рода вещей в ng2, но это трудно сказать без более подробной информации с вашей стороны.   -  person jlew    schedule 04.12.2015
comment
Я нашел этот ответ полезным: stackoverflow.com/a/31037168/1341825   -  person theUtherSide    schedule 25.05.2016


Ответы (5)


Компонент 2, компонент директивы может определять свойство ввода (аннотация @input в Typescript). И Компонент 1 может передать это свойство директивному компоненту из шаблона.

См. этот ответ SO ">Как сделать взаимодействие между основным и подробным компонентом в Angular2?

и как ввод передается дочерним компонентам. В вашем случае это директива.

person Chandermani    schedule 04.12.2015
comment
Могу ли я использовать его для компонентов, не являющихся родительско-дочерними? Например, ‹navbar›‹/navbar› ‹router-outlet›‹/router-outlet› И я хочу, чтобы все компоненты в router-outlet имели доступ к компоненту navbar, возможно ли это? - person EgorkZe; 27.04.2016
comment
@EgorkZe Для этого объект, которым вы делитесь, должен быть общим родителем этих двух компонентов. Нет другого способа поделиться объектом между одноуровневыми компонентами, как вы описали. - person Lucio Mollinedo; 20.05.2016

Для односторонней привязки данных от родителя к дочернему используйте декоратор @Input (как рекомендуется в руководстве по стилю) для указания свойства ввода в дочернем компоненте

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

и использовать привязку свойства шаблона в родительском шаблоне

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

Поскольку вы передаете объект (ссылочный тип JavaScript), любые изменения, внесенные вами в свойства объекта в родительском или дочернем компоненте, будут отражены в другом компоненте, поскольку оба компонента имеют ссылку на один и тот же объект. Я показываю это в Plunker.

Если вы переназначите объект в родительском компоненте

this.model = someNewModel;

Angular передаст ссылку на новый объект дочернему компоненту (автоматически, как часть обнаружения изменений).

Единственное, чего не стоит делать, так это переназначать объект в дочернем компоненте. Если вы сделаете это, родитель все равно будет ссылаться на исходный объект. (Если вам нужна двусторонняя привязка данных, см. 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

person Mark Rajcok    schedule 08.12.2015
comment
ты делаешь богоугодное дело! любой совет для родственных компонентов? в моем случае у меня есть 2 загруженных на корневом уровне. HeaderComponent имеет поисковый ввод, которым я хочу поделиться с компонентами в теле. - person Sonic Soul; 30.09.2016
comment
@SonicSoul, поместите данные в ссылочный тип JavaScript в родительский элемент или, если они не имеют общего родителя, поместите данные в общую службу. Для сервисного подхода вы снова можете использовать ссылочный тип JavaScript или использовать наблюдаемые объекты. - person Mark Rajcok; 01.10.2016
comment
Спасибо! Я пробую служебный маршрут ... не думал на самом деле помещать на него Observable - person Sonic Soul; 01.10.2016
comment
@Mark, мы изучили Angular1 с помощью ваших постов и снова знаем, что вы учите нас Angular2, вы круты :) - person benek; 05.01.2017
comment
Я разместил здесь двухсторонний пример привязки данных: «как мне обмениваться данными между компонентами в angular2»> stackoverflow.com/questions/31026886/ - person sancelot; 24.07.2017

вы также можете хранить свои данные в службе с сеттером и получать их через геттер

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;
    }
}
person ueman    schedule 05.04.2017
comment
Ваш ответ слишком короткий, но он подходит для отсутствия компонентов «родитель-потомок». - person Benjamin Lucidarme; 21.07.2017
comment
Это отличная идея. Я так рад, что нашел этот ответ. Особенно хорошо, если вы знаете, что ваш объект в значительной степени глобально используется во многих компонентах на странице. - person Gherman; 08.12.2017
comment
getScope() возвращает «undefined», когда я обращаюсь к нему после установки с другой страницы. Он устанавливает переменную в порядке, но не может вернуть ее обратно! Любые идеи? - person kevaljarsania; 12.07.2018
comment
Не понятно. - person Tamaghna Banerjee; 11.06.2020

Используйте выходную аннотацию

@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);
person E. Fortes    schedule 16.03.2016

Из компонента

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
            } );
    
    }    
    }

Служба данных

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

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

К компоненту

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
    }

}

person Shafeeq Mohammed    schedule 26.06.2019