Angular 循环依赖解决方案
Angular Circular Dependency Solution
我有 popupservice
可以像这样为我打开弹出组件:
export class PopupService {
alert() { this.matdialog.open(PopupAlertComponent); }
yesno() { this.matdialog.open(PopupYesNoComponent); }
custom() { this.matdialog.open(PopupCustomComponent); }
}
然后我用 this.popupservice.custom()
打开我的自定义弹出窗口。
export class HomeComponent {
constructor(private popupservice: PopupService) {}
openCustomPopup() {
this.popupservice.custom();
}
}
然后,在我的 custom
弹出组件中,我想调用我自己的 alert
弹出窗口(报告错误或其他内容):
export class CustomPopup {
constructor(private popupservice: PopupService) {}
doHttpCall() {
...do http calls...
if (callFailed) this.popupservice.alert('Call Failed');
}
}
如何解决这个循环依赖问题?
备注:
- 我已经阅读了其他问题,但我觉得我的问题是一个特定的 "help me out" 问题。尽管仍然欢迎您向我推荐其他问题。
this.popupservice.alert()
不仅仅是一个 javascript alert
,它是我自己的自定义弹出窗口,有主题和一切。
你的服务不应该知道组件,如果你的服务知道组件,那就是糟糕的设计。您应该在您的服务中有一个类似行为主题的可观察对象,并让您的组件订阅可观察对象以了解何时弹出新消息。
为您服务
message$ = new BehaviourSubject<string>(null);
以及一个将消息发送到管道的函数。
nextMessage(message: string) {
this.message$.next(message);
}
然后在您的组件中订阅 message$ observable 然后弹出。
this.messageSubscription = this.service.message$.subscribe(message => { this.popup(message); });
确保在 ngDestroy 上执行 takeUntil 或 unscbscribe。
ngOnDestroy() {
if (this.messageSubscription ) {
this.messageSubscription.unsubscribe();
}
}
您可以做的是从 PopupService
中删除弹出窗口创建逻辑。这是给你的一个小重构。
使用 PopupService
仅从应用程序的不同部分创建事件。
@Injectable()
export class PopupService {
private _alert: Subject<any> = new Subject();
private _yesno: Subject<any> = new Subject();
private _custom: Subject<any> = new Subject();
// since you didn't like the on- methods, you can do following
public readonly alert$ = this._alert.asObservable();
public readonly yesno$ = this._yesno.asObservable();
public readonly custom$ = this._custom.asObservable();
onAlert() { return this._alert.asObservable(); }
onYesno() { return this._yesno.asObservable(); }
onCustom() { return this._custom.asObservable(); }
alert(payload) { this._alert.next(payload); }
yesno(payload) { this._yesno.next(payload); }
custom(payload) { this._custom.next(payload); }
}
所以,我们有一个 PopupService
,它只发出一些带有 payload
的事件。我在这里使用 Subject
是因为以后的订阅者不需要知道之前是否有 alert
或 yesno
事件。如果你想有这样的逻辑,你可以把Subject
改成BehaviorSubject
。
创建一个名为 PopupManager
的组件并在 app.component
中使用它
app.component.ts
@Component({
selector: 'app-root',
template: `
<!-- some template -->
<app-popup-manager></app-popup-manager>
`
})
export class AppComponent {}
@Component({
selector: 'app-popup-manager',
template: '' // don't need to have template
})
export class PopupManagerComponent implements OnInit {
constructor(private matDialog: MatDialog, private popupService: PopupService) {}
ngOnInit() {
this.popupService.onAlert().subscribe(payload => {
// this.matDialog.open...
});
this.popupService.onYesno().subscribe(payload => {
// this.matDialog.open...
});
this.popupService.onCustom().subscribe(payload => {
// this.matDialog.open...
});
}
}
通过这种方式,您可以在您想要的任何组件中使用 PopupService,因为它现在是一个单独的独立服务。
为什么不应该将 Subject
暴露给外界?
你可以想到这个封装class字段。您确实可以将 _alert
暴露给外界,但您将无法控制谁以何种方式使用该主题。方法始终是提供功能同时保持对字段的一些控制的好方法。将来,您可能想要更改服务的内部结构,也许是某些主题。如果您让应用程序的其他部分直接访问字段,您将不得不进行大量重构。但是这样一来,既然你给了他们一些方法,只要你不破坏这些方法就可以了。
我有
popupservice
可以像这样为我打开弹出组件:export class PopupService { alert() { this.matdialog.open(PopupAlertComponent); } yesno() { this.matdialog.open(PopupYesNoComponent); } custom() { this.matdialog.open(PopupCustomComponent); } }
然后我用
this.popupservice.custom()
打开我的自定义弹出窗口。export class HomeComponent { constructor(private popupservice: PopupService) {} openCustomPopup() { this.popupservice.custom(); } }
然后,在我的
custom
弹出组件中,我想调用我自己的alert
弹出窗口(报告错误或其他内容):export class CustomPopup { constructor(private popupservice: PopupService) {} doHttpCall() { ...do http calls... if (callFailed) this.popupservice.alert('Call Failed'); } }
如何解决这个循环依赖问题?
备注:
- 我已经阅读了其他问题,但我觉得我的问题是一个特定的 "help me out" 问题。尽管仍然欢迎您向我推荐其他问题。
this.popupservice.alert()
不仅仅是一个 javascriptalert
,它是我自己的自定义弹出窗口,有主题和一切。
你的服务不应该知道组件,如果你的服务知道组件,那就是糟糕的设计。您应该在您的服务中有一个类似行为主题的可观察对象,并让您的组件订阅可观察对象以了解何时弹出新消息。
为您服务
message$ = new BehaviourSubject<string>(null);
以及一个将消息发送到管道的函数。
nextMessage(message: string) {
this.message$.next(message);
}
然后在您的组件中订阅 message$ observable 然后弹出。
this.messageSubscription = this.service.message$.subscribe(message => { this.popup(message); });
确保在 ngDestroy 上执行 takeUntil 或 unscbscribe。
ngOnDestroy() {
if (this.messageSubscription ) {
this.messageSubscription.unsubscribe();
}
}
您可以做的是从 PopupService
中删除弹出窗口创建逻辑。这是给你的一个小重构。
使用 PopupService
仅从应用程序的不同部分创建事件。
@Injectable()
export class PopupService {
private _alert: Subject<any> = new Subject();
private _yesno: Subject<any> = new Subject();
private _custom: Subject<any> = new Subject();
// since you didn't like the on- methods, you can do following
public readonly alert$ = this._alert.asObservable();
public readonly yesno$ = this._yesno.asObservable();
public readonly custom$ = this._custom.asObservable();
onAlert() { return this._alert.asObservable(); }
onYesno() { return this._yesno.asObservable(); }
onCustom() { return this._custom.asObservable(); }
alert(payload) { this._alert.next(payload); }
yesno(payload) { this._yesno.next(payload); }
custom(payload) { this._custom.next(payload); }
}
所以,我们有一个 PopupService
,它只发出一些带有 payload
的事件。我在这里使用 Subject
是因为以后的订阅者不需要知道之前是否有 alert
或 yesno
事件。如果你想有这样的逻辑,你可以把Subject
改成BehaviorSubject
。
创建一个名为 PopupManager
的组件并在 app.component
app.component.ts
@Component({
selector: 'app-root',
template: `
<!-- some template -->
<app-popup-manager></app-popup-manager>
`
})
export class AppComponent {}
@Component({
selector: 'app-popup-manager',
template: '' // don't need to have template
})
export class PopupManagerComponent implements OnInit {
constructor(private matDialog: MatDialog, private popupService: PopupService) {}
ngOnInit() {
this.popupService.onAlert().subscribe(payload => {
// this.matDialog.open...
});
this.popupService.onYesno().subscribe(payload => {
// this.matDialog.open...
});
this.popupService.onCustom().subscribe(payload => {
// this.matDialog.open...
});
}
}
通过这种方式,您可以在您想要的任何组件中使用 PopupService,因为它现在是一个单独的独立服务。
为什么不应该将 Subject
暴露给外界?
你可以想到这个封装class字段。您确实可以将 _alert
暴露给外界,但您将无法控制谁以何种方式使用该主题。方法始终是提供功能同时保持对字段的一些控制的好方法。将来,您可能想要更改服务的内部结构,也许是某些主题。如果您让应用程序的其他部分直接访问字段,您将不得不进行大量重构。但是这样一来,既然你给了他们一些方法,只要你不破坏这些方法就可以了。