Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We鈥檒l occasionally send you account related emails.

Already on GitHub? Sign in to your account

Routing in Angular Based Web Components using @angular/elements #34377

Open
tuckerjt07 opened this issue Dec 12, 2019 · 26 comments
Open

Routing in Angular Based Web Components using @angular/elements #34377

tuckerjt07 opened this issue Dec 12, 2019 · 26 comments
Labels
area: elements Issues related to Angular Elements area: router feature: under consideration Feature request for which voting has completed and the request is now under consideration feature: votes required Feature request which is currently still in the voting phase feature Issue that requests a new feature freq1: low
Milestone

Comments

@tuckerjt07
Copy link

馃殌 feature request

Relevant Package

This feature request is for @angular/elements and @angular/router

Description

When attempting to use an Angular app to host a second Angular app wrapped as a Web Component routing does not work for the hosted app.

Describe the solution you'd like

It would be nice if an instance of the hosting app could be passed in so that the router.forChild() could be used to register the routes for the web component. Another option would be to rework both elements and router so that multiple forRoot instances of the router do not cause issues.

Describe alternatives you've considered

I have tried named outlets and ui-router. UI-router got me the closest by using the Angular Router in the hosting application and ui-router in the hosted component. The issue I ran into there was that I could not directly navigate by URL into a sub-route using ui-router.
@kara kara added area: elements Issues related to Angular Elements area: router labels Dec 12, 2019
@ngbot ngbot bot added this to the needsTriage milestone Dec 12, 2019
@atscott atscott added freq1: low feature Issue that requests a new feature labels Dec 12, 2019
@ngbot ngbot bot modified the milestones: needsTriage, Backlog Dec 12, 2019
@tuckerjt07
Copy link
Author

I've managed to get close to what I want using the steps in this article, https://medium.com/@timon.grassl/how-to-use-routing-in-angular-web-components-c6a76449cdb . The issue is that using the named router-outlets is causing other routing issues, particularly around navigating between two primary routes to a named outlet in the second route and also with redirectUrls that contain named outlets.

@tuckerjt07
Copy link
Author

tuckerjt07 commented Dec 17, 2019

Another update, here is a gist of where I'm at with this, https://gist.github.com/tuckerjt07/8c8c7fd55208c4c23f8adb0750e15ee8. It's actually working pretty close to how I want it to. Now the only issue is I am getting some extraneous states in the browser's nav stack.

@BufferUnderrunOK
Copy link

Even with Timon Grassl's code, we still have multiple problems with deep linking to items belonging to the child applications. We really need a way for Angular applications to register their own routes with the Parent applications' Router. Think of it as the inverse of loadChildren.

@tuckerjt07
Copy link
Author

tuckerjt07 commented Jan 23, 2020

Agreed, the biggest issue I am getting now is that when my component's router is used it removes any of the history that was there before from the nav stack. After some more research it's due to manually altering the navstack with pushstate.

A solution where both router modules could be used side by side without kludges would be optimal.

@BufferUnderrunOK
Copy link

But let's just leave this as completely unimportant and move on with things nobody asked for. 馃憤

@konstantintieber
Copy link

konstantintieber commented Dec 16, 2020

My colleague @fboeller recently published a npm package for exactly this use case: https://github.com/fboeller/ngx-elements-router.

The Usage section in the readme describes step by step how it works.

We are using this approach for developing Angular microfrontends in web-components today and I'm sure he'll continue to update that package as we find new bugs/missing behaviour.

@lilletech
Copy link

I had the problem. I've removed lazy loading and used routermodule.forroot to make routing working

@rotty3000
Copy link

rotty3000 commented Apr 14, 2021

It seems fundamentally broken to not have good isolation within the routing engine. I'm not an angular expert nor even a JavaScript expert, but the mere fact that the routing engine in Angular does not apparently have any isolation after this much time is sad. I wrongly assumed that such a mature framework would just "have a solution" for this. It's not even about inheritance from one engine to another.

If an instance of a routing engine could set a base when it is instantiated and if many routing engines could set their own bases separately then creating a hierarchy of engines should flow from a parent setting the handler of one if it's routes to any other (routing engine) instance, and also support the case for peers from any other technology (i.e. other web components from other frameworks.)

My (potentially super naive) 2 cents.

@bbech
Copy link

bbech commented Apr 23, 2021

+1

@angular-robot angular-robot bot added the feature: votes required Feature request which is currently still in the voting phase label Jun 4, 2021
@angular-robot
Copy link
Contributor

angular-robot bot commented Jun 4, 2021

Just a heads up that we kicked off a community voting process for your feature request. There are 20 days until the voting process ends.

Find more details about Angular's feature request process in our documentation.

@angular-robot angular-robot bot added the feature: under consideration Feature request for which voting has completed and the request is now under consideration label Jun 5, 2021
@arjunasuresh3
Copy link

+1

2 similar comments
@marrej
Copy link

marrej commented Aug 4, 2021

+1

@rotty3000
Copy link

+1

@SchnWalter
Copy link
Contributor

Guys, please stop with the +1. On the right sidebar, you have a "Subscribe" button, please use that.

@VIDIZMO-bilal-ahmed
Copy link

Is there any progress on this issue?

@jainank
Copy link

jainank commented Mar 17, 2022

馃憤

@jainank
Copy link

jainank commented Mar 17, 2022

FYI --
To include the community in the feature request process, we open voting for 60 days. Anyone can cast a vote for the request with a thumbs-up (馃憤) reaction. When a feature request reaches 20 or more upvotes, we formally consider the feature request. Alternatively, the bot closes the request.

@marceloluzbmo

This comment was marked as off-topic.

2 similar comments
@Lindsor

This comment was marked as off-topic.

@BufferUnderrunOK

This comment was marked as off-topic.

@a29340

This comment was marked as off-topic.

2 similar comments
@TheLangdaTyagi

This comment was marked as off-topic.

@bala3011s

This comment was marked as off-topic.

@konstantintieber
Copy link

Fabian B枚ller and me just published a video that covers everything about how we ship web component-based micro frontends with Angular.

Here's the two video chapters that cover our integration of the Angular router of the surrounding application with the web component:

Link to the project on GitHub: https://github.com/fboeller/microfrontends-with-angular/tree/recording

I hope this can help to inspire the discussions on how to support this in the Angular router.

@blidblid
Copy link

blidblid commented Sep 9, 2022

If your web components are small, you could handle routing natively. It's super simplistic, but it just works.

https://gist.github.com/blidblid/b920440c7e6f68bd24a2257dca489be5

To create components, use *ngComponentOutlet over router-outlet.

@bh3605
Copy link

bh3605 commented Aug 25, 2023

Crazy this hasn't been solved yet. I'm using two standalone components in a monorepo set up and I'm sharing the same route-config between the two of them because I'm using angular-architect/mod-fed to load the 2nd stand alone component as a web component and I'm able to get the route to trigger, but the context.outlet object is null and therefore won't load the 2nd component.

root app

const routeProvider = provideRouter(routes, withDebugTracing())
setGlobalRoutes(routeProvider);

export const appConfig: ApplicationConfig = {
  providers: [
    routeProvider,
    // {provide: LocationStrategy, useClass: MultiLocationStrategy},
    {
      provide: ENVIRONMENT,
      useFactory: resolveEnvironment
    },
    importProvidersFrom(HttpClientModule, ModuleFederationToolsModule)
  ]
};

root app html

<mft-wc-wrapper [options]="item"></mft-wc-wrapper>

root app component

export class MyRootComponent {
  item: WebComponentWrapperOptions = {
    type: "manifest",
    remoteName: 'claims',
    exposedModule: 'RecentClaims',
    // elementName: "claims-recent-claims"
    elementName: 'recent-claims'
  };
}

root app routes

export const routes: Routes = [
    {
    path: 'claims',
    loadComponent: () => loadRemoteModule({
      type: "manifest",
      remoteName: "claims",
      exposedModule: "AppComponent"
    }).then(m => m.AppComponent)
  }
]

shared lib containing the setGlobalRoutes function

export const routerSubject = new BehaviorSubject<EnvironmentProviders>(null as unknown as EnvironmentProviders);

export function setGlobalRoutes(router: EnvironmentProviders) {
  routerSubject.next(router);
}

imported 2nd mfe exposed as a web component so it can be dynamically loaded. RecentClaims has a routerLink to /claims and the router almost succeeds in doing the navigation, but atlas it does not.

@Component({
  selector: 'claims-recent-claims',
  standalone: true,
  imports: [CommonModule, RouterLink],
  template: "<p>recent-claims works!</p> <a routerLink="/claims">Claims</a>"
  styleUrls: ['./recent-claims.component.css'],
  schemas: [CUSTOM_ELEMENTS_SCHEMA]
})
export class RecentClaimsComponent {
  constructor(private claimsSvc: ClaimsService) {}
}

const app = await createApplication(
  {
    providers: [
      {
        provide: ENVIRONMENT,
        useFactory: resolveEnvironment
      },
      routerSubject.getValue()
    ]
  }
);

const recentClaims = createCustomElement(RecentClaimsComponent, {
  injector: app.injector
});
customElements.define('recent-claims', recentClaims);

The reason the context.outlet is null is as you can see a lack of a router-outlet in my 2nd standalone component so Angular is searching any higher up in the dom for a router-outlet and modifying that one instead. Frustrating, hopefully I can figure something out.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
area: elements Issues related to Angular Elements area: router feature: under consideration Feature request for which voting has completed and the request is now under consideration feature: votes required Feature request which is currently still in the voting phase feature Issue that requests a new feature freq1: low
Projects
None yet
Development

No branches or pull requests