[英]Angular Circular Dependency Solution
I have popupservice
that opens popup components for me like this: 我有
popupservice
可以为我打开弹出组件,如下所示:
export class PopupService { alert() { this.matdialog.open(PopupAlertComponent); } yesno() { this.matdialog.open(PopupYesNoComponent); } custom() { this.matdialog.open(PopupCustomComponent); } }
Then I open my custom popup with this.popupservice.custom()
. 然后,我使用
this.popupservice.custom()
打开自定义弹出窗口。
export class HomeComponent { constructor(private popupservice: PopupService) {} openCustomPopup() { this.popupservice.custom(); } }
Then, in my custom
popup component I want to call my own alert
popup (to report an error or something): 然后,在我的
custom
弹出窗口组件中,我想调用自己的alert
弹出窗口(报告错误或其他内容):
export class CustomPopup { constructor(private popupservice: PopupService) {} doHttpCall() { ...do http calls... if (callFailed) this.popupservice.alert('Call Failed'); } }
How can I solve this circular dependency problem? 我该如何解决循环依赖问题?
Notes: 笔记:
this.popupservice.alert()
is not just a javascript alert
, it is my own custom popup that has a theme and everything. this.popupservice.alert()
不仅是一个JavaScript alert
,它还是我自己的自定义弹出窗口,具有主题和所有内容。 Your service should not know about components, that is bad design if your services have knowledge of components. 您的服务不应了解组件,如果您的服务具有组件知识,那将是不好的设计。 You should have an observable like a behaviour subject in your service and have your component subscribe to the observable to know when to popup a new message.
您应该在服务中拥有一个类似于行为主题的可观察对象,并使您的组件订阅该可观察对象,以知道何时弹出新消息。
In your service 为您服务
message$ = new BehaviourSubject<string>(null);
and a function to send a message down the pipeline. 以及向管道发送消息的功能。
nextMessage(message: string) {
this.message$.next(message);
}
Then in your component you subscribe to the message$ observable and then do you popup. 然后在您的组件中订阅$ observable消息,然后弹出。
this.messageSubscription = this.service.message$.subscribe(message => { this.popup(message); });
Making sure to takeUntil or unscbscribe on ngDestroy. 确保对ngDestroy进行until或unscbscribe。
ngOnDestroy() {
if (this.messageSubscription ) {
this.messageSubscription.unsubscribe();
}
}
What you can do is to take away popup creation logic from PopupService
. 您可以做的是从
PopupService
弹出创建逻辑。 Here is a little refactor for you. 这是给您的一些重构。
Use PopupService
to only create events from different parts of the application. 使用
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); }
}
So, we have a PopupService
which only emits some events with some payload
s. 因此,我们有一个
PopupService
,它只发出带有一些payload
的事件。 I used Subject
here because later subscribers won't need to know if there was a alert
or yesno
event earlier. 我在这里使用
Subject
是因为以后的订户不需要知道之前是否有alert
或yesno
事件。 If you want to have such logic, you can change Subject
to BehaviorSubject
. 如果您想拥有这样的逻辑,则可以将
Subject
更改为BehaviorSubject
。
Create a component called PopupManager
and use it in app.component
创建一个名为
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...
});
}
}
With this way, you can use PopupService in any component you want since it is a singleton, standalone service now. 通过这种方式,您可以在所需的任何组件中使用PopupService,因为它现在是单例的独立服务。
Why you should not expose Subject
s to outside world? 为什么不应该将
Subject
暴露给外界?
You can think of this encapsulating class fields. 您可以想到这种封装类字段。 You could indeed expose
_alert
to outside world but then you will have no control over who uses this subject in what way. 您确实可以将
_alert
暴露给外界,但是您将无法控制谁以何种方式使用此主题。 Methods are always great way to provide functionality while maintaining some control over the fields. 在保持对字段的某些控制的同时,方法总是提供功能的好方法。 In the future, you may want to change internals of the service, maybe some of the subjects.
将来,您可能想更改服务的内部,也许是某些主题。 If you let other parts of the application access directly on fields, you would have to refactor a lot.
如果让应用程序的其他部分直接在字段上访问,则必须进行大量重构。 But this way, since you are giving them some methods, as long as you don't break those methods you'll be fine.
但是这样,由于您为他们提供了一些方法,所以只要您不破坏这些方法,就可以了。
声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.