question-mark
Stuck on an issue?

Lightrun Answers was designed to reduce the constant googling that comes with debugging 3rd party libraries. It collects links to all the places you might be looking at while hunting down a tough bug.

And, if you’re still stuck at the end, we’re happy to hop on a call to see how we can help out.

Add `type` field to the router event object

See original GitHub issue

Which @angular/* package(s) are relevant/releated to the feature request?

router

Description

I have a piece of code that gets invoked by user with router as a parameter. In that code I subscribe to router events. If an app is minified, constructor names of events are obfuscated and then I need to do some naive checking like

function isNavigationEnd(event: Event): event is NavigationEnd {
    return event["constructor"]["name"] === RouterEvents.NAVIGATION_END
        || ("id" in event
            && typeof event["id"] === "number"
            && !!event["url"]
            && "urlAfterRedirects" in event
            && !!event["urlAfterRedirects"]
            && objectKeys(event).length === 3);
}

I am not so familiar with angular. The issue I currently have is that I do some action in RouteConfigLoadStart and keep a reference to it and I clean that reference in NavigationCancel or NavigationEnd Now for some reason NavigationEnd or NavigationCancel never happens and references keep growing when I enter the RouteConfigLoadStart. If event constructor names would be preserved I would know which event I am currently working with and could easier do the logic. Keep in mind that my piece of code is external to the angular app, and it gets called with router as a parameter, so I am not in an non obfuscated environment of the app.

Proposed solution

Add a type field to the event or preserve name of its constructor.

Alternatives considered

I am using an alternative to do the naive checking but some events have same fields and then it could match more events than it should.

Issue Analytics

  • State:closed
  • Created 2 years ago
  • Reactions:21
  • Comments:15 (8 by maintainers)

github_iconTop GitHub Comments

4reactions
clydincommented, Oct 8, 2021

Unfortunately, configuration adjustments are not easily done (i.e., not without moving off the supported path with the Angular CLI at least) and it can result in large size regressions in applications while also being complex to correctly configure. It would also require all consuming applications to be adequately configured for this particular library’s use case since the class originates from the application’s code via @angular/router and not the library’s code. Constructor/function names are not particularly reliable in the general case as different functions can have the same name but provide completely different functionality. Optimizations can also inline or otherwise modify certain code constructs resulting in names no longer existing. That is probably not overly relevant in this case but making assumptions based on name or toString, regardless of optimization, can lead to broken runtime behavior.

The addition of the type property as a type guard on the router event classes could also provide some potential ergonomic improvements as well. For example, instead of needing multiple if statements with instanceof checks when handling multiple event classes, a switch statement with type could be used instead with TypeScript narrowing based on the case statement.

2reactions
Airbladercommented, Oct 10, 2021

Just to throw in another (admittedly also not pretty) workaround: since your users need to call an init function from their Angular app, you could extend that to pass all relevant objects to which you need access:

init({
    // What you currently have
    router: this.router,

    // Plus either
    navigationEnd: NavigationEnd,
    // or
    navigationEnd: NavigationEnd.constructor.name

    // ...and for all other types you need...
});

This snippet would even always be exactly the same for the user, so to hide that you could also offer a small Angular library for them to add which wraps the init function and passes the types along internally. Since that library (which really only contains a single function) is compiled as part of their app, nothing really changes regarding how they use your library. The only thing that changes for them is that they add a tiny dependency exposing the init function rather than calling an unknown global function.

They way your actual library essentially receives a lookup table.

Read more comments on GitHub >

github_iconTop Results From Across the Web

Subscribing To Router Events In Angular - Upmostly
In anycase, it's actually fairly trivial to subscribe to router events. The first thing to do is to inject the Router object into...
Read more >
Angular 6 router.events.filter 'filter' does not exist on type ...
This is how to filter router events with Angular 6+ and latest RxJS: import { Component, OnInit } from '@angular/core'; import { Router, ......
Read more >
Value types in Apollo Federation - Apollo GraphQL Docs
Types like this are called value types. This article describes how to share value types and their fields in federated graph, enabling multiple...
Read more >
RouterEvent - Angular
A unique ID that the router assigns to every router navigation. url: string, Declared in Constructor. The URL that is the destination for...
Read more >
Embedded Event Manager Command Reference, Cisco IOS ...
Router (config)# event manager applet mat Router(config-applet)# event mat ... Specifies the type of event to monitor, cache or field.
Read more >

github_iconTop Related Medium Post

No results found

github_iconTop Related StackOverflow Question

No results found

github_iconTroubleshoot Live Code

Lightrun enables developers to add logs, metrics and snapshots to live code - no restarts or redeploys required.
Start Free

github_iconTop Related Reddit Thread

No results found

github_iconTop Related Hackernoon Post

No results found

github_iconTop Related Tweet

No results found

github_iconTop Related Dev.to Post

No results found

github_iconTop Related Hashnode Post

No results found