【问题标题】:How to share data/change between components如何在组件之间共享数据/更改
【发布时间】:2016-06-23 00:50:24
【问题描述】:

假设您有一个包含工具栏、侧边栏和网格的界面。工具栏有一个下拉菜单,当用户更改时,侧边栏和网格中的内容会发生变化。回到 Angular 1,我会使用一个服务来拥有我所有的动态数据。当服务发生变化时,使用该服务的所有组件也会更新。

在 Angular 2 中,看起来人们正在使用不同的方法。我想听听您对哪种方式是首选方式的意见。

  • 静态服务
  • OnChanges
  • 输入和输出

我剩下的问题是,最佳实践是为组件之间共享的每个数据项创建一个新服务,还是我们可以只拥有一个具有存储所有共享数据的对象的服务。

Original Plunker - 每个更改都有自己的服务

app.component.ts

import {Component} from 'angular2/core';
import {NavService} from '../services/NavService';

@Component({
  selector: 'obs-comp',
  template: `obs component, item: {{item}}`
})
export class ObservingComponent {
  item: number;
  subscription: any;
  constructor(private _navService:NavService) {}
  ngOnInit() {
    this.item = this._navService.navItem();
    this.subscription = this._navService.navChange$.subscribe(
      item => this.selectedNavItem(item));
  }
  selectedNavItem(item: number) {
    this.item = item;
  }
  ngOnDestroy() {
    this.subscription.unsubscribe();
  }
}

@Component({
  selector: 'my-nav',
  template:`
    <div class="nav-item" (click)="selectedNavItem(1)">nav 1 (click me)</div>
    <div class="nav-item" (click)="selectedNavItem(2)">nav 2 (click me)</div>
  `,
})
export class Navigation {
  item = 1;
  constructor(private _navService:NavService) {}
  selectedNavItem(item: number) {
    console.log('selected nav item ' + item);
    this._navService.changeNav(item);
  }
}

@Component({
  selector: 'my-app',
  template: `{{title}}
  <p>
  <my-nav></my-nav>
  <button (click)="showObsComp = !showObsComp">toggle ObservingComponent</button>
  <div *ngIf='showObsComp'>
    <obs-comp></obs-comp>
  </div>
  `,
  directives: [Navigation, ObservingComponent]
})
export class AppComponent {
  title = "Angular 2 - event delegation";
  showObsComp = true;
  constructor() { console.clear(); }
}

NavService.ts

import {Observable} from 'rxjs/Observable';
import 'rxjs/add/operator/share';

export class NavService {
  private _navItem = 0;
  navChange$: Observable<number>;
  private _observer: Observer;
  constructor() {
    this.navChange$ = new Observable(observer =>
      this._observer = observer).share();
    // share() allows multiple subscribers
  }
  changeNav(number) {
    this._navItem = number;
    this._observer.next(number);
  }
  navItem() {
    return this._navItem;
  }
}

index.html

<!DOCTYPE html>
<html>
  <head>
    <title>User Input</title>
    <link rel="stylesheet" href="styles.css">
    <script src="https://code.angularjs.org/2.0.0-beta.11/angular2-polyfills.js"></script>
    <script src="https://code.angularjs.org/tools/system.js"></script>
    <script src="https://code.angularjs.org/tools/typescript.js"></script>
    <script src="https://code.angularjs.org/2.0.0-beta.11/Rx.js"></script>
    <script src="https://code.angularjs.org/2.0.0-beta.11/angular2.dev.js"></script>
    <script>
      System.config({
        transpiler: 'typescript', 
        typescriptOptions: { emitDecoratorMetadata: true }, 
        packages: {
          app:      {defaultExtension: 'ts'},
          services: {defaultExtension: 'ts'},
        } 
      });
      System.import('app/boot')
            .then(null, console.error.bind(console));
    </script>
  </head>

  <body>
    <my-app>Loading...</my-app>
  </body>

</html>

app/boot.ts

import {bootstrap} from 'angular2/platform/browser';
import {AppComponent} from './app.component';
import {NavService} from '../services/NavService';

bootstrap(AppComponent, [NavService]);

Revised Plunker for example - 只有一项服务将所有数据存储在对象中。将向每个侦听器传递一个类型,以检查它是否需要根据该类型执行任何操作。

【问题讨论】:

  • 其他人提供了很好的答案,但想指出Component Interaction 上的文档部分可能也值得一读。

标签: angular


【解决方案1】:

您可以为此利用共享服务。它可以同时包含要订阅的数据和可观察对象,以便在数据更新时收到通知。

  • 服务

    export class ListService {
      list1Event: EventEmitter<any> = new EventEmitter();
    
      getLists() {
        return this.http.get(url).map(res => res.json())
          .subscribe(
            (data) => {
              this.list1Event.emit(data.list1);
            }
          );
      }
    }
    
  • 组件

    @Component({
      selector: 'my-component1',
      template: `
        <ul>
         <li *ngFor="#item of list">{{item.name}}</li>
        </ul>
      `
    })
    export class MyComponent1 {
      constructor(private service:ListService) {
        this.service.list1Event.subscribe(data => {
          this.list = data;
        });
      }
    }
    
  • 引导

    bootstrap(AppComponent, [ ListService ]);
    

查看这个问题了解更多详情:

【讨论】:

  • 很好的答案,但是正如您链接到的 eventemitter-or-observable 论坛中所述,看起来 observable 是更好的方法。我现在就试一试,看看它对我有什么作用。
【解决方案2】:

在您的用例中,我会使用服务。服务用于将其数据传递给其他组件。一个组件可以将此数据更新到服务,而另一个组件可以从中读取。或者两个组件都可以从中读取数据,然后服务器本身从“外部世界”获取数据。

您使用input 将数据从父级传递给子级,您使用output 将事件从子级输出到父级。

当组件本身发生变化时,您可以使用ngOnChanges 来执行某些操作,但我更喜欢为此使用get()set() 函数。

至少,这是我的看法:)

【讨论】:

  • 感谢您对何时使用每一个的精彩描述。这对我将来真的很方便。我将使用@Thiery 提到的 EventEmitter vs Observable 线程中提到的 Observable 服务方法。
  • 所以我有一个关于您何时使用事件与 ngOnChanges 的描述的后续问题。因此,假设我有一个使用共享 childComponent 网格的父组件。通过共享,我的意思是多个其他组件使用这个网格来显示他们自己的数据。因此,如果我希望父组件在此子组件(网格)中调用一个函数,但仅在此实例中不是所有其他函数,那么 ngOnChanges 是否是这种情况下的最佳用途?
猜你喜欢
  • 2020-08-31
  • 2021-10-12
  • 2017-06-26
  • 2018-05-15
  • 1970-01-01
  • 2020-11-08
  • 2017-10-25
相关资源
最近更新 更多