I having a problem showing my alert when triggered in ResetPasswordComponent
oninit. The subscribe block for AlertService
is not being triggered however if I move the code from oninit to the constructor it will work. However it does not seem like it's a good practice to put initialization/declaration code in the constructor. So is there a better solution to this?
Parent
export class ResetPasswordComponent implements OnInit {
public email: string;
public token: string;
constructor(public alertService: AlertService) {
}
ngOnInit() {
this.token = this.route.snapshot.queryParamMap.get('token');
this.email = this.route.snapshot.queryParamMap.get('email');
console.log("Parent on init");
if (this.token === null || this.token === "" ||
this.email === null || this.email === "") {
this.form.disable();
this.alertService.error("Invalid link");
}
}
}
Child
export class AlertComponent implements OnInit, OnDestroy {
private subscription: Subscription;
public messages: string[];
public type: string;
constructor(private alertService: AlertService) {
}
ngOnInit() {
console.log(this.alertService.getAlert());
this.subscription = this.alertService.getAlert().subscribe(data => {
console.log("OK");
// do something
});
console.log("Child On init");
}
ngOnDestroy() {
this.subscription.unsubscribe();
}
}
AlertService
@Injectable({ providedIn: 'root' })
export class AlertService {
private subject = new Subject<Alert>();
constructor(private router: Router) { }
error(message: any, navigateTo = null) {
if (navigateTo !== null) {
this.navigateWithMessage(navigateTo, AlertType.error, message);
}
const alert: Alert = { type: AlertType.error, message };
this.subject.next(alert);
console.log("NEXT");
}
getAlert(): Observable<Alert> {
return this.subject.asObservable();
}
I believe the problem is that the event is triggered before the child component has started subscribing in the ngOnInit. When the child component finally subscribes, the "Invalid link" event has already happened and is finished.
There is a couple of solutions to this, one is changing your Subject to a BehaviorSubject, like:
private subject = new BehaviorSubject<Alert>(null);
Now, as soon as the child subscribes, it will receive the last event from the Observable, even after the event has happened.
Another solution could be adding the shareReplay() operator to your observable. But in this specific case, when you are already using subjects, I would go with the BehaviorSubject solution.