簡體   English   中英

如何在 Angular 2 中的組件之間共享數據?

[英]How do I share data between components in Angular 2?

在 Angular 1.xx 中,您只需請求相同的服務,最終得到相同的實例,從而可以在服務中共享數據。

現在在 Angular 2 中,我有一個引用我的服務的組件。 我可以讀取和修改服務中的數據,這很好。 當我嘗試在另一個組件中注入相同的服務時,似乎我得到了一個新實例。

我究竟做錯了什么? 是模式本身錯誤(使用服務共享數據)還是我需要將服務標記為單例(在應用程序的一個實例中)或其他什么?

我在2.0.0-alpha.27/順便說一句

我通過@Component注釋中的appInjector (編輯:現在providers )注入一個服務,然后在構造函數中保存一個引用。 它在組件中本地工作 - 只是不像我想象的那樣跨組件(它們不共享相同的服務實例)。

UPDATE:角2.0.0,因為我們現在有@ngModule,你會下的定義服務providers在上述財產@ngModule 這將確保該服務的相同實例被傳遞給該模塊中的每個組件、服務等。 https://angular.io/docs/ts/latest/guide/ngmodule.html#providers

更新:一般來說,Angular 和 FE 開發發生了很多事情。 正如@noririco 提到的,你也可以使用像 NgRx 這樣的狀態管理系統: https ://ngrx.io/

服務單例是一個不錯的解決方案。 其他方式 - data/events bindings

這是兩者的示例:

class BazService{
  n: number = 0;
  inc(){
    this.n++;
  }
}

@Component({
  selector: 'foo'
})
@View({
  template: `<button (click)="foobaz.inc()">Foo {{ foobaz.n }}</button>`
})
class FooComponent{
  constructor(foobaz: BazService){
    this.foobaz = foobaz;
  }
}

@Component({
  selector: 'bar',
  properties: ['prop']
})
@View({
  template: `<button (click)="barbaz.inc()">Bar {{ barbaz.n }}, Foo {{ prop.foobaz.n }}</button>`
})
class BarComponent{
  constructor(barbaz: BazService){
    this.barbaz = barbaz;
  }
}

@Component({
    selector: 'app',
    viewInjector: [BazService]
})
@View({
  template: `
    <foo #f></foo>
    <bar [prop]="f"></bar>
  `,
  directives: [FooComponent, BarComponent]
})
class AppComponent{}

bootstrap(AppComponent);

觀看直播

@maufarinelli 的評論值得自己回答,因為在我看到它之前,即使有了@Alexander Ermolov 的回答,我仍然在用這個問題把頭撞在牆上。

問題在於,當您向component添加providers

@Component({
    selector: 'my-selector',
    providers: [MyService],
    template: `<div>stuff</div>`
})

這會導致您的服務的一個新實例被注入......而不是成為一個單例

因此,在您的應用程序中刪除您的providers: [MyService]所有實例,除了在module ,它會起作用!

您必須使用 @Component 裝飾器的輸入和輸出。 這是使用兩者的最基本示例;

import { bootstrap } from 'angular2/platform/browser';
import { Component, EventEmitter } from 'angular2/core';
import { NgFor } from 'angular2/common';

@Component({
  selector: 'sub-component',
  inputs: ['items'],
  outputs: ['onItemSelected'],
  directives: [NgFor],
  template: `
    <div class="item" *ngFor="#item of items; #i = index">
      <span>{{ item }}</span>
      <button type="button" (click)="select(i)">Select</button>
    </div>
  `
})

class SubComponent {
  onItemSelected: EventEmitter<string>;
  items: string[];

  constructor() {
    this.onItemSelected = new EventEmitter();
  }

  select(i) {
    this.onItemSelected.emit(this.items[i]);
  }
}

@Component({
  selector: 'app',
  directives: [SubComponent],
  template: `
    <div>
      <sub-component [items]="items" (onItemSelected)="itemSelected($event)">
      </sub-component>
    </div>
  `
})

class App {
  items: string[];

  constructor() {
    this.items = ['item1', 'item2', 'item3'];
  }

  itemSelected(item: string): void {
    console.log('Selected item:', item);
  }
}

bootstrap(App);

在父組件模板中:

<hero-child [hero]="hero">
</hero-child>

在子組件中:

@Input() hero: Hero;

來源: https : //angular.io/docs/ts/latest/cookbook/component-communication.html

有很多方法。 這是一個使用父元素和子元素之間傳播的示例。 這是非常有效的。

我提交了一個示例,該示例允許查看兩種表單中兩種數據綁定方式的使用情況。 如果有人可以提供 plunkr 樣本,那就太好了;-)

您可以通過服務提供商尋找另一種方式。 您也可以觀看此視頻以供參考:(在 Angular 中的組件之間共享數據

mymodel.ts(要共享的數據)

// Some data we want to share against multiple components ...
export class mymodel {
    public data1: number;
    public data2: number;
    constructor(
    ) {
        this.data1 = 8;
        this.data2 = 45;
    }
}

請記住:必須有一個父組件將“mymodel”共享給子組件。

父組件

import { Component, OnInit } from '@angular/core';
import { mymodel } from './mymodel';
@Component({
    selector: 'app-view',
    template: '<!-- [model]="model" indicates you share model to the child component -->
        <app-mychild [model]="model" >
        </app-mychild>'

        <!-- I add another form component in my view,
         you will see two ways databinding is working :-) -->
        <app-mychild [model]="model" >
        </app-mychild>',
})

export class MainComponent implements OnInit {
    public model: mymodel;
    constructor() {
        this.model = new mymodel();
    }
    ngOnInit() {
    }
}

子組件,mychild.component.ts

import { Component, OnInit,Input } from '@angular/core';
import { FormsModule }   from '@angular/forms'; // <-- NgModel lives here
import { mymodel } from './mymodel';

@Component({
    selector: 'app-mychild',
    template: '
        <form #myForm="ngForm">
            <label>data1</label>
            <input type="number"  class="form-control" required id="data1 [(ngModel)]="model.data1" name="data1">
            <label>val {{model.data1}}</label>

            label>data2</label>
            <input  id="data2"  class="form-control" required [(ngModel)]="model.data2" name="data2" #data2="ngModel">
            <div [hidden]="data2.valid || data2.pristine"
                class="alert alert-danger">
                data2 is required
            </div>

            <label>val2 {{model.data2}}</label>
        </form>
    ',
})

export class MychildComponent implements OnInit {
    @Input() model: mymodel ;  // Here keywork @Input() is very important it indicates that model is an input for child component
    constructor() {
    }
    ngOnInit() {
    }
}

注意:在極少數情況下,解析 HTML 代碼時可能會出錯,因為模型在頁面初始化時還沒有“准備好”使用。 在這種情況下,在 HTML 代碼前加上 ngIf 條件:

<div *ngIf="model"> {{model.data1}} </div>

這取決於,如果有一個簡單的案例

a) A -> B -> CA 有兩個孩子 B 和 C,如果你想在 A 和 B 或 A 和 C 之間共享數據,那么使用 (input / output)

如果你想在 B 和 C 之間共享,那么你也可以使用(輸入/輸出),但建議使用服務。

b) 如果樹又大又復雜。 (如果有這么多級別的父子連接。)在這種情況下,如果您想共享數據,那么我建議使用ngrx

它實現了flux 架構,該架構創建了一個客戶端存儲,任何組件都可以訂閱該存儲並可以在不創建任何競爭條件的情況下進行更新。

暫無
暫無

聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.

 
粵ICP備18138465號  © 2020-2024 STACKOOM.COM