7

My question title might be a bit confusing, so hopefully the following details will clear it up.
Essentially, the navigation bar is out of my control and it is written in just plain HTML/JS. My application is written in Angular and has routing set up within it.

Is there anything I can do to trigger routing in my Angular app from the nav bar?

Say I have the following in index.html:

<body>
    <header>
        <a onclick="history.pushState({}, '', '/home');">Home</a>
        <a onclick="history.pushState({}, '', '/test');">Test</a>
    </header>
    <app-root></app-root>
</body>

Obviously, my Angular application starts from <app-root> and does not know about the tag right above it. However, is there a way to affect the routing within the Angular from outside of it?

I figured that calling history.pushState() would change it, but it doesn't seem to be doing anything. It does change the URL, but the component displayed on the browser stays the same. It does not switch the component.

Does anyone have a solution to this problem?
I really appreciate the help!

2
  • Is your base href set in the head tag? What is it? angular.io/docs/ts/latest/guide/router.html#base-href Commented Feb 28, 2017 at 17:07
  • @Will It is set. In my example app (where my method I described in the question isn't working), it's just set to <base href="/" /> Commented Feb 28, 2017 at 17:09

4 Answers 4

9

If someone is looking for a potential solution, here's a solution I was recommended in another forum. Maybe there's a better way to do it and improve upon it, but here's what I have so far:

In app.component.ts (or wherever you want to handle routing):

declare var window: any;

//@Component stuff...
export class AppComponent implements OnInit, OnDestroy {

    routerSubject: Subject<string> = new Subject<string>();

    constructor(private router: Router) {
        // Assign the observable to the window object, so that we can call it from outside
        window.routerSubject = this.routerSubject;
    }

    ngOnInit() {
        this.routerSubject.subscribe((url: string) => {
            // Programmatically navigate whenever a new url gets emitted.
            this.router.navigate([`/${url}`]);
        });
    }

    ngOnDestroy() {
        this.routerSubject.unsubscribe();
    }
}

Now, in index.html:

<body>
    <header>
        <!-- Emit a new value on click, so that Angular (which has already been subscribed) can programmatically route -->
        <a onclick="window.routerSubject.next('home');">Home</a>
        <a onclick="window.routerSubject.next('about');">About</a>
    </header>
    <app-root></app-root>
</body>

Obviously, you can put your onclick method in a seperate JS file, and put the Angular routing logic in a service, etc etc. But this is the general gist of the solution I came up with.

Either way, this should enable people to route an Angular app from the outside.

Sign up to request clarification or add additional context in comments.

3 Comments

This is great, but I'd love to see more details here, for example, where did you get Subject, also it should be implements, not extends, also val should be url... but where did you get Subject? Nm, found it in 'rxjs/Subject', anyways, thanks for finding the solution despite all of the naysayers
@SerjSagan I have made the corrections. Thanks for pointing them out.
Many thanks! It works for me. We are using both - Angular 1.3 and Angular 7. I had an issue that you have click routing link twice to work with Angular 7. For now it is fixed
2

You can achieve this without making any code changes:

// Simulate navigation to where you want to be (changes URL but doesn't navigate)
window.history.pushState("","","/url");

// Simulate navigation again so that
window.history.pushState("","","/url");

// when you simulate back, the router tries to get BACK to "/url"
window.history.back();

This works for both old Angular (Angular.js) and new Angular, as well as for many other frameworks that use client-side routing.

Source: Calling React Router from vanilla JS

Comments

0

Building on @GJW's answer: if we push the state, navigate back, wait till navigation happens and navigate forward, then Angular will pick up the change.

Code in practice:

let listener = () => {
    window.removeEventListener("popstate", listener);
    window.history.forward();
};
window.addEventListener("popstate", listener, { once: true });

window.history.pushState({}, "", "/workflow/assistant/1/upload");
window.history.back();

Note: We have to remove the eventlistener before calling history.forward() otherwise it enters an infinite loop. I had {once:true}, but that did not help, I assume it only removes the listener after it ran. Anyway I left it in for safety and good manners.

Comments

-1

why not just use your url to navigate?

<header>
    <a href="http://www.yoursite.com/#/home">Home</a>
    <a href="http://www.yoursite.com/#/about">About</a>
</header>

Comments

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.