将 属性 公开为可观察对象的最简单语法?
Simplest syntax for exposing a property as an observable?
我在 Angular 中看过教程,展示了无数种实现可观察对象的不同方法。就我的目的而言,其中许多似乎过于复杂。其他的适用于以前的版本,不再有效。
假设我有一个名为 numChickens
的单个 属性 服务,我想允许组件订阅该 属性。 Do.i.really((need)=> 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,什么是最简单,最直接,最易读的方式来暴露chickens
属性在ChickenService这样的组件 class 可以访问 属性 作为可观察流的值?或者组件模板可以使用异步管道显示值?
我怎么强调都不过分 - 拜托,没有包含 8,192 个字符的闭包墙然后说 "see, it's simple".
的答案
我问这个问题不仅是为了我自己,也是为了像我这样的其他人,他们正试图围绕可观察的事物进行思考,并在所有关于该主题的密集和过时的教程中苦苦挣扎。如果你能把这个解决方案简化为一个简单的形式,后代会感谢你。
如果你真的想将它作为流公开,你所要做的就是添加一行:
import { Injectable } from '@angular/core';
import { of } from 'rxjs';
@Injectable({
providedIn: 'root'
})
export class ChickenService {
public chickens: number;
public chickens$ = of(chickens);
constructor() { }
}
请注意,这样做仍然不允许您更新值,因此这样做没有太多附加价值。
您可以使用主题来更新值并通过订阅流在 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);
}
}
注意:我尽量避免在不必要时显式使用主题。
最简单的方法是创建一个私有 Subject
,然后用它来创建您的 public Observable
。
在下面的代码中,我为您的 chickens
变量创建了 get
和 set
。这意味着每次您使用(例如)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;
}
}
您可以考虑使用装饰器将 属性 变成可观察对象。这样做的细节并不是特别有趣,但是一旦你完成了,你就可以写出类似这样的东西:
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); }
}
});
};
}
我在 Angular 中看过教程,展示了无数种实现可观察对象的不同方法。就我的目的而言,其中许多似乎过于复杂。其他的适用于以前的版本,不再有效。
假设我有一个名为 numChickens
的单个 属性 服务,我想允许组件订阅该 属性。 Do.i.really((need)=> 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,什么是最简单,最直接,最易读的方式来暴露chickens
属性在ChickenService这样的组件 class 可以访问 属性 作为可观察流的值?或者组件模板可以使用异步管道显示值?
我怎么强调都不过分 - 拜托,没有包含 8,192 个字符的闭包墙然后说 "see, it's simple".
的答案我问这个问题不仅是为了我自己,也是为了像我这样的其他人,他们正试图围绕可观察的事物进行思考,并在所有关于该主题的密集和过时的教程中苦苦挣扎。如果你能把这个解决方案简化为一个简单的形式,后代会感谢你。
如果你真的想将它作为流公开,你所要做的就是添加一行:
import { Injectable } from '@angular/core';
import { of } from 'rxjs';
@Injectable({
providedIn: 'root'
})
export class ChickenService {
public chickens: number;
public chickens$ = of(chickens);
constructor() { }
}
请注意,这样做仍然不允许您更新值,因此这样做没有太多附加价值。
您可以使用主题来更新值并通过订阅流在 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);
}
}
注意:我尽量避免在不必要时显式使用主题。
最简单的方法是创建一个私有 Subject
,然后用它来创建您的 public Observable
。
在下面的代码中,我为您的 chickens
变量创建了 get
和 set
。这意味着每次您使用(例如)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;
}
}
您可以考虑使用装饰器将 属性 变成可观察对象。这样做的细节并不是特别有趣,但是一旦你完成了,你就可以写出类似这样的东西:
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); }
}
});
};
}