Rxjs 订阅在 Angular 指令中不起作用
Rxjs Subscription does not work in a Angular Directive
考虑以下代码:
@Component({
selector: 'cdt-angular-loader',
templateUrl: 'loader.component.html',
styleUrls: ['loader.component.scss']
})
export class LoaderComponent implements OnInit, OnDestroy {
public show = false;
private subscription: Subscription;
constructor(private _loaderService: LoaderService) {
}
ngOnInit() {
// subscribe to the service state to hide/show the loader
this.subscription = this._loaderService.loaderState
.subscribe((state: LoaderState) => {
this.show = state.show;
});
}
ngOnDestroy() {
// unsubscribe
this.subscription.unsubscribe();
}
}
订阅按预期工作,每当 loaderService 调用 next() 时都会引发订阅。
但是,如果我在指令而不是组件中使用相同的代码,则永远不会引发订阅:
@Directive({
selector: '[cdtSaving]'
})
export class SavingDirective implements OnInit, OnDestroy {
private subscription: Subscription;
constructor(private _loaderService: LoaderService, private _elRef: ElementRef, private _renderer: Renderer) { }
ngOnInit() {
// this._renderer.setElementAttribute(this._elRef.nativeElement, 'disabled', 'true');
// subscribe to the service state to hide/show the loader
this.subscription = this._loaderService.loaderState
.subscribe((state: LoaderState) => {
alert('state changed:' + state.show);
});
}
ngOnDestroy() {
// unsubscribe
this.subscription.unsubscribe();
}
}
调用了 ngOnInit 并创建了订阅,但从未调用订阅,尽管它在组件中。
难道它不应该以与指令相同的方式工作吗?
[编辑]
根据@Vikas 的评论,我将 LoaderService 更改为使用 BehaviorSubject 而不是 Subject。现在订阅在第一次加载指令时被调用。但是每当服务执行 next() 时,订阅都不会被调用。我不确定为什么...
这是 loaderService 的代码,它的价值....
@Injectable()
export class LoaderService {
private loaderSubject = new BehaviorSubject<LoaderState>({ show: false});
public loaderState = this.loaderSubject.asObservable();
constructor() { }
show() {
this.loaderSubject.next(<LoaderState>{ show: true });
}
hide() {
this.loaderSubject.next(<LoaderState>{ show: false });
}
}
我注意到,只要我在 top-level 模块中使用该指令,我的代码就绝对可以正常工作,即使使用该指令也是如此。如果我在 lazy-loaded 模块中使用它,它就不起作用。
这很奇怪,因为服务是提供给 lazy-loaded 模块的,所以理论上这应该可行。知道为什么会这样吗?
[编辑]
回答参见
事实证明订阅者不能很好地与 lazy-loaded 模块一起工作。我不得不将我的服务提升到应用程序模块。现在可以了。
考虑以下代码:
@Component({
selector: 'cdt-angular-loader',
templateUrl: 'loader.component.html',
styleUrls: ['loader.component.scss']
})
export class LoaderComponent implements OnInit, OnDestroy {
public show = false;
private subscription: Subscription;
constructor(private _loaderService: LoaderService) {
}
ngOnInit() {
// subscribe to the service state to hide/show the loader
this.subscription = this._loaderService.loaderState
.subscribe((state: LoaderState) => {
this.show = state.show;
});
}
ngOnDestroy() {
// unsubscribe
this.subscription.unsubscribe();
}
}
订阅按预期工作,每当 loaderService 调用 next() 时都会引发订阅。
但是,如果我在指令而不是组件中使用相同的代码,则永远不会引发订阅:
@Directive({
selector: '[cdtSaving]'
})
export class SavingDirective implements OnInit, OnDestroy {
private subscription: Subscription;
constructor(private _loaderService: LoaderService, private _elRef: ElementRef, private _renderer: Renderer) { }
ngOnInit() {
// this._renderer.setElementAttribute(this._elRef.nativeElement, 'disabled', 'true');
// subscribe to the service state to hide/show the loader
this.subscription = this._loaderService.loaderState
.subscribe((state: LoaderState) => {
alert('state changed:' + state.show);
});
}
ngOnDestroy() {
// unsubscribe
this.subscription.unsubscribe();
}
}
调用了 ngOnInit 并创建了订阅,但从未调用订阅,尽管它在组件中。
难道它不应该以与指令相同的方式工作吗?
[编辑]
根据@Vikas 的评论,我将 LoaderService 更改为使用 BehaviorSubject 而不是 Subject。现在订阅在第一次加载指令时被调用。但是每当服务执行 next() 时,订阅都不会被调用。我不确定为什么... 这是 loaderService 的代码,它的价值....
@Injectable()
export class LoaderService {
private loaderSubject = new BehaviorSubject<LoaderState>({ show: false});
public loaderState = this.loaderSubject.asObservable();
constructor() { }
show() {
this.loaderSubject.next(<LoaderState>{ show: true });
}
hide() {
this.loaderSubject.next(<LoaderState>{ show: false });
}
}
我注意到,只要我在 top-level 模块中使用该指令,我的代码就绝对可以正常工作,即使使用该指令也是如此。如果我在 lazy-loaded 模块中使用它,它就不起作用。
这很奇怪,因为服务是提供给 lazy-loaded 模块的,所以理论上这应该可行。知道为什么会这样吗?
[编辑]
回答参见
事实证明订阅者不能很好地与 lazy-loaded 模块一起工作。我不得不将我的服务提升到应用程序模块。现在可以了。