What you can do is to take away popup creation logic from PopupService. Here is a little refactor for you.
Use PopupService to only create events from different parts of the application.
@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 payloads. I used Subject here because later subscribers won't need to know if there was a alert or yesno event earlier. If you want to have such logic, you can change Subject to BehaviorSubject.
Create a component called PopupManager and use it in 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.
Why you should not expose Subjects to outside world?
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. 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.
this.matdialog.open(PopupAlert);