将属性公开为可观察的最简单语法?

时间:2018-07-29 06:18:57

标签: angular typescript angular-observable

我看过一些教程,这些教程展示了在Angular中实现可观察对象的多种不同方法。就我的目的而言,其中许多似乎过于复杂。其他版本则适用于以前的版本,不再起作用。

比方说,我有一个带有名为numChickens的单个属性的服务,并且我希望允许组件订阅该属性。是否真的要(真的需要(=)to.chain((a)=> {million.garbledyGook()。statements.to('gether)})来做到这一点?

这是有关服务的代码:

import { Injectable } from '@angular/core';

@Injectable({
  providedIn: 'root'
})

export class ChickenService {

  public chickens: number; 

  constructor() { }

}

...这是将使用可观察的组件的代码:

import { Component, OnInit } from '@angular/core';
import { ChickenService } from '../chicken.service';

@Component({
  selector: 'app-chickendisplay',
  templateUrl: './chickendisplay.component.html',
  styleUrls: ['./chickendisplay.component.scss']
})

export class ChickenDisplayComponent implements OnInit {

  constructor(public cs: ChickenService) {
  }

  ngOnInit() {
  }

}

在Angular 6中,最简单,最直接,最易读的方法是在ChickenService中公开chickens属性,以便组件类可以按如下方式访问该属性的值:可观察的流?还是使组件模板可以使用异步管道显示值?

我不能强调那么多-请不要回答,包括一个8192个字符的闭包墙,然后说“看,很简单”。

我不仅向自己问这个问题,还向像我这样的其他人问这个问题,这些人试图将头围在可观察物上,并在有关该主题的所有密集且过时的教程中苦苦挣扎。如果您可以将此解决方案简化为简单的形式,子孙后代将感谢您。

3 个答案:

答案 0 :(得分:1)

如果您真的想将其公开显示为流,那么您要做的就是添加一行:

import { Injectable } from '@angular/core';
import { of } from 'rxjs';

@Injectable({
  providedIn: 'root'
})
export class ChickenService {

  public chickens: number; 
  public chickens$ = of(chickens);
  constructor() { }
}

请注意,这样做仍然不允许您更新值,因此这样做没有太多附加值。

您可以使用Subject来订阅流,以更新值并在UI中反映这些更改:

import { Injectable } from '@angular/core';
import { of } from 'rxjs';

@Injectable({
  providedIn: 'root'
})
export class ChickenService {

  public chickens: number;

  public chickens$ = chickensSub$.asObservable();
  private chickensSub$ = new BehaviorSubject();
  constructor() { }

  updateChickens(value: number) {
    this.chichensSub$.next(value);
  }
}

注意:我尽量避免在不必要时明确使用主题。

答案 1 :(得分:1)

最简单的方法是创建一个私有Subject,并使用它来创建您的公共Observable

在下面的代码中,我为您的get变量创建了setchickens。这意味着每次您使用(例如)service.chickens = 10更新它时,它将使用新值自动触发Observable流上的新事件。

import { Injectable } from '@angular/core';
import { Subject, Observable } from 'rxjs';

@Injectable({
  providedIn: 'root'
})

export class ChickenService {

  private _chickens: number; // Make this private so we can expose it via a get/set
  private chickenChange$ = new Subject<number>(); // This will be used to create our Observable
  public chickens$ = this.chickenChange$.asObservable(); // This is our Observable

  constructor() { }

  set chickens(val: number) {
    this._chickens = val; // Set the new value
    this.chickenChange$.next(val); // Trigger the subject, which triggers the Observable
  }

  get chickens() {
    return this._chickens;
  }

}

答案 2 :(得分:1)

您可能会考虑使用装饰器将属性变为可观察的属性。这样做的细节并不是特别有趣,但是一旦完成,您将可以编写如下内容:

export class ChickenService {
  @Observablize()
  public chickens: number; 

  public chickens$: Observable<number>;
}

好,现在深吸一口气。装饰器的实现大致如下(未试用)。

function Observablize() {
  return function (target, propertyKey: string, descriptor: PropertyDescriptor) {
    const observableKey = propertyKey + "$";
    const privateKey = propertyKey + "_";

    Object.defineProperties(target.prototype, {
      [observableKey]: { value: new Subject<any>() },
      [propertyKey]: { 
        get() { return this[privateKey]; },
        set(v) { this[privateKey] = v; this[observableKey].next(v); }
      }
    });
  };
}