Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Angular Material Routed Dialog with Routed Tabs

To start: my StackBlitz contains the exact case I'm trying to solve.

Like the title says I have a routed dialog (dialog that opens based on the route) and inside this dialog I want to have a tab control. Every tab should also be bound to a route, so I think my dialog should somehow also get a <router-outlet/>

But when I add this extra <router-outlet/> without the name argument the rendering (I think) goes frenzy -> result: unresponsive app.

When I add the name argument and I also configure the routing it doesn't work either.

const routes: Routes = [
  {path: '', redirectTo: '/home', pathMatch: 'full'},
  {path: 'home', component: HomeComponent, children: [
    {path: 'dialog', component: DialogWrapperComponent},
    {path: 'routed-dialog',
     children: [
       {path: '', component: RoutedDialogWrapperComponent},
       {path: 'first', component: FirstComponent 
          //, outlet:'test' // Adding this does not work
       }
     ]
    }
  ]},
]

So, the RoutedDialogWrapperComponent looks like this:

import { Component } from "@angular/core";
import { MatDialog } from "@angular/material/dialog";
import { RoutedDialogComponent } from "./routed-dialog.component";
import { Router, ActivatedRoute } from "@angular/router";

@Component({
  template:''
})
export class RoutedDialogWrapperComponent{
  constructor(private dialog:MatDialog, private router:Router,
    private route: ActivatedRoute){
    this.openDialog();
  }

  private openDialog(){
    let dialog = this.dialog.open(RoutedDialogComponent);

    dialog.afterClosed().subscribe(result => {
      this.router.navigate(['../'],
        {
          relativeTo: this.route
        });
    });
  }
}

and the HTML of the RoutedDialogComponent like this:

<nav mat-tab-nav-bar>
  <a mat-tab-link routerLink="/home/dialog2/first">First</a>
  <a mat-tab-link>Second</a>
  <a mat-tab-link>Third</a>
</nav>

<!-- without name it rendering goes wild and will hang -->
<router-outlet name='test'></router-outlet>

<!-- this router-outlet does not work ... -->
<!-- 
  <router-outlet></router-outlet>
-->

In the end I want to have an url like: '/home/routed-dialog/first' and inside the dialog, under the tab-nav, I want to see the FirstComponent but I don't know how to...

Other cases like having the correct tab 'activated' is something I'm confident enough about to fix, but on this one I need some help because my Angular knowledge (as goes for its slang) is pretty limited :-)

like image 304
321X Avatar asked Mar 03 '23 04:03

321X


1 Answers

You can find solution with named router outlets here 'router-outlet' in MatDialog is not working in Angular 7

But if you really want to have clean links without strange constructions like /routed-dialog(popupContent:first) then you can do the following trick:

  • define all tabbed components as children of RoutedDialogWrapperComponent:

    {
      path: "routed-dialog",
      component: RoutedDialogWrapperComponent,
      children: [
        {
          path: "first",
          component: FirstComponent
        },
        {
          path: "second",
          component: SecondComponent
        },
        {
          path: "third",
          component: ThirdComponent
        },
        {
          path: '**',
          redirectTo: 'first'
        }
      ],
    }
    
  • put <router-outlet> in template of RoutedDialogWrapperComponent and wrap it with <ng-template>

    <ng-template>
      <router-outlet></router-outlet>
    </ng-template>
    
  • grab reference to that wrapper in component class:

    export class RoutedDialogWrapperComponent {
      @ViewChild(TemplateRef, { static: true }) templateRef: TemplateRef<any>;
    
  • pass that reference to RoutedDialogComponent:

    export class RoutedDialogWrapperComponent implement OnInit {
       ngOnInit() {
         this.openDialog();
       }
    
       private openDialog() {
         const dialog = this.dialog.open(RoutedDialogComponent);
         dialog.componentInstance.contentTemplate = this.templateRef;
         ...
       }
    }
    
  • finally, render it within RoutedDialogComponent:

    <nav mat-tab-nav-bar>
      <a mat-tab-link routerLink="home/routed-dialog/first">First</a>
      <a mat-tab-link routerLink="home/routed-dialog/second">Second</a>
      <a mat-tab-link routerLink="home/routed-dialog/third">Third</a>
    </nav>
    
    <ng-template [ngTemplateOutlet]="contentTemplate"></ng-template>
    

Forked Stackblitz

like image 80
yurzui Avatar answered Mar 11 '23 03:03

yurzui