Implement routing with steps component in a dynamic dialog priemng

95 Views Asked by At

Could anyone help me with implementing a steps component in a dynamic dialog in primeng. I am working on a sample project where I need to implement login screen in a dialog box that includes multiple steps like entering basic information in first step and then entering more details about the user in next steps.

I would like to navigate to different components as I move from one step to another while staying in the dynamic dialog box.

Any general directions is much appreciated. Thank you

1

There are 1 best solutions below

9
NgDaddy On BEST ANSWER

I think it is achievable this way:

Root App component bootstraping:

@Component({
  selector: 'app-root',
  standalone: true,
  template: `
    <h1>Hello from {{ name }}!</h1>
    <router-outlet></router-outlet>
  `,
  imports: [RouterOutlet],
})
export class App {
  name = 'Angular';
}

bootstrapApplication(App, {
  providers: [
    /**
     * DialogService must be provided in the component that is about to open the dialog - the component injector is taken in order to keep router-outlets in the right order
     */
    // DialogService,
    provideAnimations(),
    provideRouter([
      {
        path: '',
        loadComponent: () =>
          import('./components/my-page/my-page.component').then(
            (c) => c.MyPageComponent
          ),
        children: [
          {
            path: '',
            pathMatch: 'full',
            redirectTo: 'step-one',
          },
          {
            path: 'step-one',
            loadComponent: () =>
              import(
                './components/my-page/steps/1-step-one/step-one.component'
              ).then((c) => c.StepOneComponent),
          },
          {
            path: 'step-two',
            loadComponent: () =>
              import(
                './components/my-page/steps/2-step-two/step-two.component'
              ).then((c) => c.StepTwoComponent),
          },
          {
            path: 'step-three',
            loadComponent: () =>
              import(
                './components/my-page/steps/3-step-three/step-three.component'
              ).then((c) => c.StepThreeComponent),
          },
        ],
      },
    ]),
  ],
});

Style.scss:

@import 'primeng/resources/themes/lara-light-blue/theme.css';
@import 'primeng/resources/primeng.css';
@import 'primeicons/primeicons.css';
@import 'primeflex/primeflex.css';

Page component that will show the dialog:

<ng-container
  *ngIf="dynamicDialog; else dialogTpl"
  [ngTemplateOutlet]="dynamicDialogTpl"
></ng-container>

<ng-template #dialogTpl>
  <button
    type="button"
    (click)="showDialog()"
    pButton
    icon="pi pi-info-circle"
    label="Show dialog"
    [disabled]="dialogVisible"
  ></button>
  <p-dialog position="top" [(visible)]="dialogVisible">
    <app-steps-dialog></app-steps-dialog>
  </p-dialog>
</ng-template>

<ng-template #dynamicDialogTpl>
  <button
    type="button"
    (click)="showDynamicDialog()"
    pButton
    icon="pi pi-info-circle"
    label="Show dynamic dialog"
    [disabled]="dynamicDialogVisible"
  ></button>
</ng-template>

@Component({
  templateUrl: './my-page.component.html',
  standalone: true,
  imports: [
    ButtonModule,
    DialogModule,
    StepsDialogComponent,
    NgIf,
    NgTemplateOutlet,
  ],
  /**
   * DialogService must be provided in the component that is about to open the dialog - the component injector is taken in order to keep router-outlets in the right order
   */
  providers: [DialogService],
})
export class MyPageComponent implements OnInit {
  /**
   * a switch between dialog an dynamicDialog
   */
  dynamicDialog = true;

  dialogVisible: boolean = true;
  dynamicDialogVisible: boolean = false;

  private destroyRef = inject(DestroyRef);
  private dialogService = inject(DialogService);

  private dynamicDialogRef: DynamicDialogRef | undefined;

  private viewContainerRef = inject(ViewContainerRef);

  ngOnInit() {}

  showDialog(): void {
    if (!this.dynamicDialog) {
      this.dialogVisible = true;
    }
  }

  showDynamicDialog(): void {
    if (this.dynamicDialog) {
      this.dynamicDialogVisible = true;
      this.dynamicDialogRef = this.dialogService.open(StepsDialogComponent, {
        appendTo: this.viewContainerRef.element.nativeElement,
        data: {
          dynamic: true,
        },
      });
      this.dynamicDialogRef.onClose
        .pipe(
          tap(() => {
            this.dynamicDialogVisible = false;
            this.dynamicDialogRef = void 0;
          }),
          takeUntilDestroyed(this.destroyRef)
        )
        .subscribe();
    }
  }
}

Steps Dialog Component:

<div class="card">
  <p-steps [model]="items" [readonly]="false"></p-steps>
  <router-outlet></router-outlet>
</div>

@Component({
  selector: 'app-steps-dialog',
  templateUrl: './steps-dialog.component.html',
  standalone: true,
  imports: [StepsModule, ButtonModule, RouterOutlet],
})
export class StepsDialogComponent {
  items: MenuItem[] = [
    { label: 'Step One', routerLink: 'step-one' },
    { label: 'Step Two', routerLink: 'step-two' },
    { label: 'Step Three', routerLink: 'step-three' },
  ];

  dynamicDialogConfig = inject(DynamicDialogConfig, { optional: true });

  constructor() {
    console.log('dynamicDialogConfig', this.dynamicDialogConfig);
  }
}

Step One component:

<h2>Step One</h2>
<div class="flex justify-content-end">
  <p-button icon="pi pi-chevron-right" routerLink="/step-two"></p-button>
</div>

@Component({
  templateUrl: './step-one.component.html',
  standalone: true,
  imports: [RouterLink, ButtonModule],
})
export class StepOneComponent {}

Step Two component:

<h2>Step Two</h2>
<div class="flex justify-content-between">
  <p-button icon="pi pi-chevron-left" routerLink="/step-one"></p-button>
  <p-button icon="pi pi-chevron-right" routerLink="/step-three"></p-button>
</div>

@Component({
  templateUrl: './step-two.component.html',
  standalone: true,
  imports: [RouterLink, ButtonModule],
})
export class StepTwoComponent {}

And Step Three component:

<h2>Step Three</h2>
<div class="flex justify-content-start">
  <p-button icon="pi pi-chevron-left" routerLink="/step-two"></p-button>
</div>

@Component({
  templateUrl: './step-three.component.html',
  standalone: true,
  imports: [RouterLink, ButtonModule],
})
export class StepThreeComponent {}

And the last but not least :) stackblitz@demo