我有一个组件,它通过异步管道将可观察值(test$)打印到模板。
组件属性需要根据组件的输入进行初始化,因此我将其值分配给ngOnInit中服务(test$)发出的可观察对象。服务公开的可观察对象在服务初始化时被分配给主题的组合。该值不会打印在模板中。Stackblitz
如果我将组合的主题定义为行为主题,则会通知模板新值。
我认为这与冷/热可观察对象有关。我的理解是,如果你订阅一个行为主题,即使你在它发出一个值之后订阅,你也总是会得到最新的值,但是对于冷可观察对象(作为主题),你需要在值发出之前订阅,以便得到通知。
那么,如果订阅发生在主体发出值之前,为什么模板不会被更新呢?我的推理是,订阅发生在模板渲染完成时,这是在ngOnInit中。主体直到这一步之后才会发出它们的值。
组件
@Component({
selector: 'my-app',
templateUrl: './app.component.html',
styleUrls: [ './app.component.css' ]
})
export class AppComponent {
@Input() initialValue: number;
result$: Observable<number>;
constructor(private service: TestService) {
}
ngOnInit() {
console.log('component init');
this.result$ = this.service.result$;
// Get data based on inputs
this.service.initTransformedValue(this.initialValue);
}
}
服务
@Injectable()
export class TestService {
result$: Observable<number>;
otherValue$: Observable<number>;
transformedValue$: Observable<number>;
constructor() {
console.log('service constructor');
this.init();
}
init(){
this.result$ = combineLatest(
this.transformedValue$,
this.otherValue$
).pipe(map(([first, second]) => {
console.log('have combined value');
return first + second;
})
);
}
initTransformedValue(initialValue) {
// Use timeout to simulate HTTP calls
setTimeout(() => {
console.log('service. emit transformedValue value');
this.transformedValue$ = of(initialValue * 2);
}, 1000);
setTimeout(() => {
console.log('service. emit otherValue value');
this.otherValue$ = of(initialValue * 4);
}, 1200);
}
}
模板
<p>{{result$ | async}}</p>
您正在使用of创建一个新的可观察对象,您需要使当前可观察对象发出一个新值。
https://stackblitz.com/edit/angular-fta9h1
你永远不应该将一个可观察对象与另一个可观察对象重新分配,你应该使现有的可观察对象发射,主体和行为主体可以通过调用next来发射。
const { of, BehaviorSubject } = rxjs;
let obs = of('of initial value');
obs.subscribe(val => { console.log(val); });
// This is a new observable and will not effect the subscription to a different obsevable
obs = of('of new value');
const bs = new BehaviorSubject('BehaviorSubject initial value');
bs.subscribe(val => { console.log(val); });
// This emits a new value on the same observable
bs.next('BehaviorSubject new value');
<script src="https://cdnjs.cloudflare.com/ajax/libs/rxjs/6.4.0/rxjs.umd.min.js"></script>