如何在Angular 2中的组件之间共享数据?

如何在Angular 2中的组件之间共享数据?,angular,typescript,Angular,Typescript,在Angular 1.x.x中,您只需请求相同的服务,最终得到相同的实例,从而可以共享服务中的数据 现在在Angular 2中,我有一个组件引用了我的服务。我可以读取和修改服务中的数据,这很好。当我尝试在另一个组件中注入相同的服务时,似乎得到了一个新实例 我做错了什么?模式本身是错误的(使用服务共享数据)还是我需要将服务标记为单例(在应用程序的一个实例中)还是其他什么 我在2.0.0-alpha.27/顺便说一句 我通过@Component注释中的appInjector(编辑:现在provide

在Angular 1.x.x中,您只需请求相同的服务,最终得到相同的实例,从而可以共享服务中的数据

现在在Angular 2中,我有一个组件引用了我的服务。我可以读取和修改服务中的数据,这很好。当我尝试在另一个组件中注入相同的服务时,似乎得到了一个新实例

我做错了什么?模式本身是错误的(使用服务共享数据)还是我需要将服务标记为单例(在应用程序的一个实例中)还是其他什么

我在
2.0.0-alpha.27/
顺便说一句

我通过
@Component
注释中的
appInjector
(编辑:现在
providers
)注入服务,然后在构造函数中保存引用。它在组件中本地工作——只是不像我想象的那样跨组件(它们不共享同一个服务实例)

更新:从Angular 2.0.0开始,我们现在有了@ngModule,您可以在所述
@ngModule
上的
提供者
属性下定义服务。这将确保将该服务的相同实例传递给该模块中的每个组件、服务等。

更新:一般来说,在角度和FE开发方面发生了很多事情。正如@noririco所提到的,您还可以使用NgRx这样的状态管理系统:
服务单例是一个很好的解决方案。其他方式-
数据/事件绑定

以下是两者的一个示例:

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);
class服务{
n:数字=0;
公司(){
这个.n++;
}
}
@组成部分({
选择器:“foo”
})
@看法({
模板:`Foo{{foobaz.n}}`
})
类组件{
建造商(foobaz:BazService){
this.foobaz=foobaz;
}
}
@组成部分({
选择器:“条”,
属性:['prop']
})
@看法({
模板:`Bar{{barbaz.n}},Foo{{{prop.foobaz.n}}`
})
类BarComponent{
建造商(barbaz:BazService){
this.barbaz=barbaz;
}
}
@组成部分({
选择器:“应用程序”,
viewInjector:[BazService]
})
@看法({
模板:`
`,
指令:[FooComponent,BarComponent]
})
类AppComponent{}
bootstrap(AppComponent);

服务单例是一个很好的解决方案。其他方式-
数据/事件绑定

以下是两者的一个示例:

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);
class服务{
n:数字=0;
公司(){
这个.n++;
}
}
@组成部分({
选择器:“foo”
})
@看法({
模板:`Foo{{foobaz.n}}`
})
类组件{
建造商(foobaz:BazService){
this.foobaz=foobaz;
}
}
@组成部分({
选择器:“条”,
属性:['prop']
})
@看法({
模板:`Bar{{barbaz.n}},Foo{{{prop.foobaz.n}}`
})
类BarComponent{
建造商(barbaz:BazService){
this.barbaz=barbaz;
}
}
@组成部分({
选择器:“应用程序”,
viewInjector:[BazService]
})
@看法({
模板:`
`,
指令:[FooComponent,BarComponent]
})
类AppComponent{}
bootstrap(AppComponent);

必须使用@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);
从'angular2/platform/browser'导入{bootstrap};
从'angular2/core'导入{Component,EventEmitter};
从'angular2/common'导入{NgFor};
@组成部分({
选择器:'子组件',
输入:[“项目”],
输出:['onItemSelected'],
指令:[NgFor],
模板:`
{{item}}
挑选
`
})
类子组件{
onItemSelected:EventEmitter;
项目:字符串[];
构造函数(){
this.onItemSelected=neweventemitter();
}
选择(i){
this.onItemSelected.emit(this.items[i]);
}
}
@组成部分({
选择器:“应用程序”,
指令:[子组件],
模板:`
`
})
类应用程序{
项目:字符串[];
构造函数(){
this.items=['item1','item2','item3'];
}
itemSelected(项目:字符串):无效{
console.log('所选项目:',项目);
}
}
引导(App);

必须使用@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);
从'angular2/platform/browser'导入{bootstrap};
从'angular2/core'导入{Component,EventEmitter};
从'angular2/common'导入{NgFor};
@组成部分({
选择器:'子组件',
输入:[“项目”],
输出:['onItemSelected'],
指令:[NgFor],
模板:`
{{item}}
挑选
`
})
类子组件{
onItemSelected:EventEmitter;
项目:字符串[];
构造函数(){
this.onItemSelected=neweventemitter();
}
选择(i){
this.onItemSelected.emit(this.items[i]);
}
}
@组成部分({
选择器:“应用程序”,
指令:[子组件],
模板:`
`
})
类应用程序{
项目:字符串[];
构造函数(){
this.items=['item1','item2','item3'];
}
itemSelected(项目:字符串):无效{
console.log('所选项目:',项目);
}
}
引导(App);

Maufarineli的评论应该有自己的答案,因为在我看到它之前,即使有@Alexander Ermolov的答案,我仍然在用这个问题把头撞在墙上

问题是,当您向
组件添加
提供程序时:

@Component({
    selector: 'my-selector',
    providers: [MyService],
    template: `<div>stuff</div>`
})
@组件({
选择器:“我的选择器”,
提供者:[MyService],
模板:`东西`
})
这将导致注入服务的新实例。。。而不是成为一名教师


因此,请删除应用程序中除
模块
之外的
提供者:[MyService]
的所有实例,它将正常工作

Maufarineli的评论应该有自己的答案,因为在我看到它之前,即使有@Alexander Ermolov的答案,我仍然在用这个问题的头撞墙

问题是,当您向
组件添加
提供程序时:

@Component({
    selector: 'my-selector',
    providers: [MyService],
    template: `<div>stuff</div>`
})
@组件({
选择器:“我的选择器”,
提供者:[MyService],
模板:`东西`
})
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() {
    }
}
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() {
    }
}
<div *ngIf="model"> {{model.data1}} </div>