使用适当的更改跟踪将服务 属性 绑定到组件 属性

Bind a service property to a component property with proper change tracking

考虑完全简单的 Angular2 服务:

import { Injectable } from '@angular/core';
import {Category} from "../models/Category.model";

@Injectable()
export class CategoryService {
    activeCategory: Category|{} = {};
    constructor() {};
}

然后是使用该服务的组件:

import { Component, OnInit } from '@angular/core';
import {CategoryService} from "../shared/services/category.service";
import {Category} from "../shared/models/Category.model";

@Component({
    selector: 'my-selector',
    template: `
    {{categoryService.activeCategory.Name}}<br/>
    {{category.Name}}<br/>
`,
})
export class MySelectorComponent implements OnInit {
    category:Category|{} = {};

    constructor(public categoryService:CategoryService){};

    ngOnInit() {
        this.category = this.categoryService.activeCategory;
    };
}

假设适当定义了类别模型,并假设某个地方的另一个组件在某个时候将服务上的 activeCategory 设置为有效类别。假设类别服务被设置为适当更高级别的提供者。

发生这种情况时,模板中的第一行将正确显示类别名称,但第二行不会。我尝试过在服务上使用 getter 和 setter 与原始访问;我尝试过原始类型与对象与对象属性;我无法相信第一行是此类访问的合适范例。有人能告诉我将服务 属性 绑定到组件 属性 的最简单方法,该方法将在 angular 两次中正确地进行更改跟踪吗?

澄清:我知道我可以使用我自己创建和推送的可观察对象。我要问的是,是否有任何一种已经嵌入到框架中的方法(不需要我为可观察对象编写大量样板文件),它只是在服务和组件之间建立了可变轨道.

Observables 可以在没有太多样板的情况下使用 Behaviors.

@Injectable() 
export class CategoryService {
  activeCategory:BehaviorSubject<{category:Category}> = new BehaviorSubject({category:null});
  // or just `Subject` depending on your requirements
}
@Component({
  selector: 'my-selector',
  template: `
  {{(categoryService.activeCategory | async)?.Name}}<br/>
`,
})
export class MySelectorComponent implements OnInit {
  constructor(public categoryService:CategoryService){};
}

您也可以只绑定到服务的属性

@Component({
  selector: 'my-selector',
  template: `
  {{categoryService?.activeCategory?.Name}}<br/>
`,
})
export class MySelectorComponent implements OnInit {
  constructor(public categoryService:CategoryService){};
}    

使用 Elvis(或安全导航)运算符,如果 activeCategory 稍后才获取值,例如当异步调用完成时,您不会收到错误消息。

样板块不是太大。 但是这里发生的事情是,当服务被创建或者你拨打电话时,你想如何处理它。您的组件将通过订阅了解它,然后将您的本地变量更新为新值。允许您以 this.activeCategory.

的形式访问它
import { Injectable } from '@angular/core';
import {Category} from "../models/Category.model";
import {Subscription}   from 'rxjs/Subscription';

@Injectable()
export class CategoryService {
    private _categoryObject = new Subject<any>();
    categoryObjectAnnounced$ = this._categoryObject;
    private _activeCategoryObject = new Subject<any>();
    activeCategoryObjectAnnounced$ = this._activeCategoryObject;
    activeCategory: Category|{} = {};
    constructor() {};
}


import { Component, OnInit } from '@angular/core';
import {CategoryService} from "../shared/services/category.service";
import {Category} from "../shared/models/Category.model";
import {Subscription} from 'rxjs/Subscription';
@Component({
    selector: 'my-selector',
    template: `
    {{activeCategory.Name}}<br/>
    {{category.Name}}<br/>
`,
})
export class MySelectorComponent implements OnInit {
    category:Category|{} = {};
    activeCategory:ActiveCategory|{} = {};
    activeCategorySubscription : Subscription;
    categorySubscription : Subscription;
    constructor(public categoryService:CategoryService){
          this.categorySubscription= this.categoryService.categoryObjectAnnounced$.subscribe((category) => {
             this.category= category;
          });

          this.activeCategorySubscription= this.categoryService.activeCategoryObjectAnnounced$.subscribe((active) => {
             this.activeCategory= active;
          });
    };
    ngOnInit() {

    };
}

您可以尝试将 ngOnInit() 替换为 ngDoCheck()。我不确定(实际上我怀疑)这是正确的做法,无论如何你可以尝试。

这种方法在每个变化检测周期都是 运行(而不是我猜的标准 Angular 算法,这是潜在的问题)因此你应该 category MySelectorComponent 的 属性 更新了服务的变化。

再次需要注意副作用(我不清楚)。