Angular: external URL navigation with dynamic parameters using guards

Angular: external URL navigation with dynamic parameters using guards

Today I want to show you a possibility to navigate to external URLs with dynamic parameters. I’ve used something like this in my previous and also in my current project, so I thought to blog about (kudos for my colleagues). The core idea is to have dedicated routes with route parameters in the usual routing module and then use a guard to handle the parameter replacement and redirection. To provide the replacement parameters dynamically during navigation, the solution will use the state property of the router NavigationExtras, which comes in handy for us here.

Let’s show the code first:

@Injectable()
export class ExternalRouteGuard implements CanActivate, CanActivateChild {
    constructor(private readonly router: Router) {}

    canActivate(route: ActivatedRouteSnapshot): boolean {
        let url: string = route.data.url || route.params.url;

        // append dynamic query params
        if (route.queryParams) {
            const queryString = Object.entries(route.queryParams)
                .map(entry => entry.join('='))
                .join('&');
            if (queryString) {
                url += `?${queryString}`;
            }
        }

        // evaluate and replace dynamic route parameters (:param)
        const replacements = this.router.getCurrentNavigation().extras.state || {};
        if (replacements) {
            const replaceRegex = /:(.*?)(\/|\?|$)/g;
            let replaceMatch = replaceRegex.exec(url);
            while (replaceMatch != null) {
                const replaceParam = replaceMatch[1];
                const replacement = replacements[replaceParam];
                if (replacement) {
                    url = url.replace(`:${replaceParam}`, replacement);
                }
                replaceMatch = replaceRegex.exec(url);
            }
        }

        // navigate to constructed URL
        const windowTarget: string = route.data.target || '_self';
        window.open(url, windowTarget);

        return false;
    }

    canActivateChild(route: ActivatedRouteSnapshot): boolean {
        return this.canActivate(route);
    }
}

First, we determine the URL to which we want to navigate. This can be set statically in the data of the route definition or provided dynamically inside the route params. Second, we append query params which are provided dynamically with the router.navigate() call.

Next, we replace the URL params provided in a :param form in the URL. We retrieve the actual values from the router state using router.getCurrentNavigation().extras.state. Then we look up all parameters which want to be replaced and replace them (if a replacement value was provided).

In the last step, we navigate to the final URL using window.open().

Using this guard is very easy: just place it in your routing-module for the routes you want to navigate to externally. I’ve found it convenient to have a separate „external“ parent route with the guard and then child routes for every concrete external URL:

...
{
    path: 'external',
    canActivateChild: [ExternalRouteGuard],
    children: [
        {
            path: 'another-frontend',
            data: {
                url: '/another-frontend/user/:userId'
                target: '_blank'
            }
        },
        {
            path: 'www'
        }
    ]
}

Now you can navigate to those URLs very easily:

router.navigate(['external','another-frontend'], {state: {userId: 123}});
router.navigate(['external','another-frontend'], {
    state: {userId: 123}, 
    queryParams: {q: 'anything'}
});
...
router.navigate(['external', 'www', {url: 'https://www.any-public.url'}]);
Ich bin freiberuflicher Senior Full-Stack Web-Entwickler (Angular, TypeScript, C#/.NET) im Raum Frankfurt/Main. Mit Leidenschaft für Software-Design, Clean Code, moderne Technologien und agile Vorgehensmodelle.

0 Kommentare

Eine Antwort hinterlassen

Deine E-Mail-Adresse wird nicht veröffentlicht. Erforderliche Felder sind mit * markiert.

*

Diese Website verwendet Akismet, um Spam zu reduzieren. Erfahre mehr darüber, wie deine Kommentardaten verarbeitet werden.