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
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