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

时间:2016-05-20 15:58:02

标签: angular angular2-services

考虑完全简单的Angular 2服务:

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设置为有效的类别。假设categoryservice被设置为适当更高级别的提供者。

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

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

3 个答案:

答案 0 :(得分:15)

Observable可以在没有太多样板的情况下使用Behavior s。

@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仅在以后获取值,例如异步调用完成时,则不会收到错误。

答案 1 :(得分:3)

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

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

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

答案 2 :(得分:0)

没有太大的样板块。 但是这里发生的事情是,当创建服务或者你打电话时,你想要处理它。您的组件将通过订阅了解它,然后将您的本地变量更新为新值。允许您以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() {

    };
}