angularpromiseguardsubject

It raise wired error when i use subject in the route guard for angular project


I created unsaved.guard.ts to make it as guard to ask user if they want give up saving data when the user quit the editing page.

when i run the project, it keeps telling me , return type error. But it looks fine. Please anyone can give me some clues, also below the whole project in the git: https://github.com/codezj/angular-route-guard

unsaved.guard.ts

import { Component, Injectable } from "@angular/core";
import {CanActivate,
    ActivatedRouteSnapshot,RouterStateSnapshot,Router, UrlTree, TitleStrategy
} from "@angular/router"

import { MessageService } from "../messages/message.service";
import { Message } from "../messages/message.model";

import { Observable, Subject } from "rxjs";

import { FormComponent } from "./form.component";

@Injectable()
export class UnsavedGuard implements CanActivate{
    constructor(private messages: MessageService, private router: Router){

    }
    canActivate(component: FormComponent, route: ActivatedRouteSnapshot, state: RouterStateSnapshot): boolean | UrlTree | Observable<boolean | UrlTree> | Promise<boolean | UrlTree>   {
        if (component.editing){
            if (["name","category","price"]
            .some(prop=> component.product["name"]
                != component.originalProduct["name"]))
                
                {
                    let subject = new Subject<boolean>();

                    let responses : [string, (string: any )=> void][] =[
                        ["Yes", () => {
                            subject.next(true);
                            subject.complete();
                        }],
                        ["No", ()=>{
                            this.router.navigateByUrl(this.router.url);
                            subject.next(false);
                            subject.complete();
                        }

                        ]
                    ];
                    this.messages.reportMessage(
                        new Message("Discard Changes?",
                    true, responses));
                    return subject;
                }
                // else {
                //     return true;
                // }
        }
        return true;
    }


}

Complied Error Message ->


Build at: 2022-12-11T05:51:15.893Z - Hash: 9449b56719e1a6f8 - Time: 721ms

Error: src/app/core/unsaved.guard.ts:18:5 - error TS2416: Property 'canActivate' in type 'UnsavedGuard' is not assignable to the same property in base type 'CanActivate'.
  Type '(component: FormComponent, route: ActivatedRouteSnapshot, state: RouterStateSnapshot) => boolean | UrlTree | Observable<...> | Promise<...>' is not assignable to type '(route: ActivatedRouteSnapshot, state: RouterStateSnapshot) => boolean | UrlTree | Observable<boolean | UrlTree> | Promise<...>'.

18     canActivate(component: FormComponent, route: ActivatedRouteSnapshot, state: RouterStateSnapshot): boolean | UrlTree | Observable<boolean | UrlTree> | Promise<boolean | UrlTree>   {
       ~~~~~~~~~~~




× Failed to compile.


I tried to change different return types for the guard functions. Not solved the issue.

Actually, when i use below way in another guard, it works fine.

import { Injectable } from "@angular/core";
import {CanActivate,
    ActivatedRouteSnapshot,RouterStateSnapshot,Router, UrlTree, TitleStrategy
} from "@angular/router"

import { MessageService } from "./messages/message.service";
import { Message } from "./messages/message.model";
import { TmplAstRecursiveVisitor } from "@angular/compiler";
import { Observable } from "rxjs";

@Injectable()
export class TermsGuard implements CanActivate {
    constructor(private messages: MessageService,
        private router: Router){}
    canActivate(route: ActivatedRouteSnapshot, state: RouterStateSnapshot): boolean | UrlTree | Observable<boolean | UrlTree> | Promise<boolean | UrlTree> {
        // throw new Error("Method not implemented.");
        if (route.params["mode"] == "create") {
            return new Promise<boolean>((resolve)=>{

                let responses: [string, ()=> void][]
                =[["Yes",()=> resolve(true)], ["No", ()=> resolve(false)]];
    
                this.messages.reportMessage(new Message("Do you accept the terms @ conditions?", false,responses))
            });
        }
        else {
            return true;
        }
    }

    // canActivte(route: ActivatedRouteSnapshot, state: RouterStateSnapshot):
    // Promise<boolean> | boolean {
    // }

    canActivateChild(route: ActivatedRouteSnapshot, state: RouterStateSnapshot):
    Promise<boolean> | boolean {
        if (route.url.length>0 
            && route.url[route.url.length-1].path == "categories"){
            return new Promise<boolean>((resolve, reject) =>{

                let responses: [string, (string:any)=>void][] = [
                    ["Yes", ()=> resolve(true)],
                    ["No ",()=>resolve(false)]
                ];
                this.messages.reportMessage(
                    new Message("Do you want to see the categories component?", false, responses)
                ) 
            })
        }
        else {
            return true;
        }
    }
}

Solution

  • You can't have a component as a parameter of the canActivate function. It has to be implemented with only two parameters: route: ActivatedRouteSnapshot and state: RouterStateSnapshot. The error message tells exactly that.