Create a dynamic dialog primed for implementing routing along with a steps component

Seeking assistance with integrating a steps component into a dynamic dialog using primeng. I'm currently developing a project that requires a login screen within a dialog box with various steps, such as entering basic information in the first step and additional user details in subsequent steps.

I aim to smoothly transition between components as I progress through each step within the dynamic dialog box.

Any guidance or advice would be greatly valued. Thank you in advance.

Answer №1

I believe this is the way to achieve it:

Starting with the 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),
          },
        ],
      },
    ]),
  ],
});

Styling in Style.scss:

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

Next, we have the Page component responsible for displaying 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,
  ],
  providers: [DialogService],
})
export class MyPageComponent implements OnInit {
  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();
    }
  }
}

The Steps Dialog Component structure:

<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);
  }
}

Details of 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 {}

Details of 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 {}

Last but not least, details of 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 {}

Feel free to check out the working demo on StackBlitz

 

Similar questions

If you have not found the answer to your question or you are interested in this topic, then look at other similar questions below or use the search

Using conditional assignment in TypeScript is similar to using Kotlin's `when` statement

I'm just starting to dabble in TypeScript and exploring its various language features. One thing that I find lacking is a 'when' expression or conditional assignment, similar to the following: const language = "DE"; const test = (language: ...

The different kinds of 'min' properties do not align. In this case, the type 'null' cannot be replaced with the type 'number' or 'undefined'

To install ngx-currency, you can run the following command: npm install ngx-currency. Next, copy and paste the code snippet below into the app.module.ts file under the section labeled set option globally... import { CurrencyMaskInputMode, NgxCurrencyMo ...

Discovering potential types in Typescript through optional inference

Uncertain if the question is formulated correctly, but I am attempting to deduce the result type without knowing exactly how to achieve it. This is my current approach: type StateSetter<S> = (prevState: S) => S; type ResolvableHookState<S> ...

The properties 'paginator' and 'sort' are missing an initial value

Struggling to implement a form filter similar to the one shown on a specific website, I encountered some code issues in my own environment. Check out this data table example with sorting, pagination, and filtering. @ViewChild(MatPaginator) paginator: MatP ...

Methods to troubleshoot problem of angular component loading issue in firefox with ViewEncapsulation.Native

I am encountering a problem with loading an angular component using ViewEncapsulation.Native in firefox, edge, and ipad chrome. Interestingly, there is no issue on safari on mac, chrome on windows, or chrome on android. Error: hostEl.createShadowRoot is ...

What is the most effective method for creating Typescript type predicates that yield the most specific types when filtering arrays?

I believed I had discovered the perfect method for defining predicates: declare function isNumber<T>(x: T): x is Extract<T, number>; declare function isFunction<T>(x: T): x is Extract<T, Function>; ... and so forth This technique l ...

The class names in Material-UI seem to constantly shuffle whenever I refresh the page

Right now I am experimenting with Text Fields in Material-UI and my goal is to make them smaller in size. For reference, here is an example of the class name: .eKdARe.header .input-container input After making changes in my file and refreshing the page, ...

Is it possible to send a variable to the controller through UI-Router and ui-sref?

Is it possible to pass multiple variables through the UI-Router for use in a state's controller? In the HTML, I have <li class="blist-item grid-loader" ng-repeat="item in items"> <a ui-sref="item({ id: {{item.$id}} })"><h3>{{it ...

Troubleshooting issue: Angular 7 form template not resetting with form.reset()

I'm having trouble resetting the input value and ngmodel control state in my form. Here's the code from TrackPage.html: <form #trackForm="ngForm"> <div class="form__field" style="padding-top: 10px; "> <search-in ...

Guide on navigating to a specific step within a wizard using Vue and TypeScript

In this wizard, there are 6 steps. The last step includes a button that redirects the user back to step 4 when clicked. The user must then complete steps 5 and 6 in order to finish the wizard. step6.ts <router-link to="/stepFour" ...

Introducing Location Injection in Angular Testing

I am using Location injection in my Angular component to redirect the user to another route. The functionality works well, but when I execute the tests, I encounter the following error message: Error: StaticInjectorError(DynamicTestModule)[CreateGroupCo ...

Error: Attempting to add types to an object returned from the .map function in JSX Element

When attempting to include the item type in the object returned from the .map function, I encountered a JSX error. I tried specifying item: JSX.Element as the Item type, but this didn't resolve the issue. Can someone provide clarity on this matter? Th ...

Deducing Generics in Typescript Functions Without Invocation of the Function

Take a look at the code snippet below; it seems like it should work without any issues. But for some reason, there is an error. Can anyone provide any insights into why this might be happening? Check out the TS-playground link const func_returnsInput = ( ...

I am facing an issue with my useFetch hook causing excessive re-renders

I'm currently working on abstracting my fetch function into a custom hook for my Expo React Native application. The goal is to enable the fetch function to handle POST requests. Initially, I attempted to utilize and modify the useHook() effect availab ...

Navigating to a different page in Angular.js using a personalized URL and query parameters

I am looking to navigate from PageB back to PageA with a specific queryString in order to track the user's previous page using an onClick event that triggers a function called 'functionName'. $stateProvider .state('edit-blo ...

Tips on utilizing a connected service in a custom Azure DevOps extension's index.ts file

I have created a unique extension for Azure DevOps that includes a specialized Connected Service and Build task. When setting up the task through the pipeline visual designer, I am able to utilize the Connected Service to choose a service and then populate ...

Elevate the Appearance of Material UI Elements with custom CSS Sty

I am currently facing an issue while trying to customize the styling of a Material UI component using CSS. Here is the code snippet: <IconButton className="my-class"> <Close /> </IconButton> CSS: .my-class { float: right ...

Is there a way to prevent the leaderboard from resetting each time I restart my client?

Is it possible to prevent the leaderboard from resetting every time I restart my client? You can see an example here: https://i.stack.imgur.com/2nEPw.png Please disregard the "undefined" error, I will correct it. In the current setup, the leaderboard onl ...

Creating tests for subscription within the onInit() method in an Angular component

In my Spinner Component class, I have implemented a functionality to show/hide Progress Spinner using Angular Material. Below is the code snippet for the class: export class SpinnerComponent implements OnInit, OnDestroy { visible = true; private s ...

Creating a header row in a CSV file with Angular 4/Typescript

Currently, I have a code snippet that retrieves data and saves it to a CSV file. However, the issue is that it's writing the data in columns rather than in a header row. I attempted toggling the 'showLabels' option between true and false to ...