首页 文章

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

提问于
浏览
69

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

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

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

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

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

UPDATE :从Angular 2.0.0开始,我们现在有@ngModule,您可以在 @ngModule 上的 providers 属性下定义服务 . 这将确保将该服务的相同实例传递给该模块中的每个组件,服务等 . https://angular.io/docs/ts/latest/guide/ngmodule.html#providers

5 回答

  • 9

    服务单身人士是一个很好的解决方案 . 其他方式 - 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);
    

    Watch live

  • 52

    @maufarinelli的评论应该得到自己的答案,因为直到我看到它,即使用@Alexander Ermolov的答案,我仍然仍然用这个问题抨击我的头 .

    问题是,当您向 component 添加 providers 时:

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

    这会导致您的服务的新实例被注入...而不是singleton .

    因此,除了 module 之外,删除应用程序中 providers: [MyService] 的所有实例,它将起作用!

  • 43

    您必须使用@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);
    
  • 2

    在父组件模板中:

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

    在子组件中:

    @Input() hero: Hero;
    

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

  • 6

    有很多方法 . 这是使用父元素和子元素之间传播的示例 . 这非常有效 .

    我提交了一个示例,允许在两种形式中查看两种数据绑定方式的用法 . 如果有人可以提供一个plunkr样本,这将是非常好的;-)

    您可以使用服务提供商寻找其他方式 . 您也可以查看此视频以供参考:(Sharing Data between Components in 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>
    

相关问题