Create wizard using accordion in Angular Accordion component

28 Sep 202324 minutes to read

Accordion items can be disabled dynamically by passing the index and boolean value with the enableItem method and also dynamically expand the item using expandItem method.

The below Wizard sample is designed for Online Shopping model. In this, each Accordion item is integrated with required components to fill the details and designed for getting user details and making payment at the end. Each field is provided with validation for all mandatory option to enable/disable to next Accordion. In below sample, accordion items can be disabled dynamically with enableItem method using created event.

<ejs-dialog #alertDlg header='Alert' width=200 isModal=true content='' [target]='dlgTarget' [buttons]='dlgButtons'
    (created)='dlgCreated()'></ejs-dialog>

<ejs-accordion #accordion (created)='acrdnCreated()'>
    <e-accordionitems>
        <e-accordionitem expanded='true' header='Sign In'>
            <ng-template #content>
                <div id="Sign_In_Form" style="padding: 3px 0">
                    <form id="formId">
                        <div class="form-group">
                            <div class="e-float-input">
                                <input type="text" id="email" name="Email" required="" #emailRef/>
                                <span class="e-float-line"></span>
                                <label class="e-float-text" for="email">Email</label>
                            </div>
                            <div class="e-float-input">
                                <input id="password" type="password" name="Password" required="" #passwordRef/>
                                <span class="e-float-line"></span>
                                <label class="e-float-text" for="password">Password</label>
                            </div>
                        </div>
                    </form>
                    <div style="text-align: center">
                        <button class='e-btn' id="Continue_Btn" (click)='btnClick($event)'>Continue</button>
                        <div id="err1" #error1>* Please fill all fields</div>
                    </div>
                </div>
            </ng-template>
        </e-accordionitem>
        <e-accordionitem header='Delivery Address'>
            <ng-template #content>
                <div id="Address_Fill" style="padding: 3px 0">
                    <form id="formId_Address">
                        <div class="form-group">
                            <div class="e-float-input">
                                <input type="text" id="name" name="Name" required="" #nameRef/>
                                <span class="e-float-line"></span>
                                <label class="e-float-text" for="name">Name</label>
                            </div>
                        </div>
                        <div class="form-group">
                            <div class="e-float-input">
                                <input type="text" id="address" name="Address" required="" #addressRef/>
                                <span class="e-float-line"></span>
                                <label class="e-float-text" for="address">Address</label>
                            </div>
                        </div>
                        <div class="form-group">
                            <ejs-numerictextbox #mobile format='0' placeholder='Mobile' floatLabelType='Auto'
                                [showSpinButton]=false></ejs-numerictextbox>
                        </div>
                    </form>
                    <div style="text-align: center">
                        <button class='e-btn' id="Continue_BtnAdr" (click)='btnClick($event)'>Continue</button>
                        <div id="err2" #error2>* Please fill all fields</div>
                    </div>
                </div>
            </ng-template>
        </e-accordionitem>
        <e-accordionitem header='Card Details'>
            <ng-template #content>
                <div id="Card_Fill" style="padding: 3px 0;">
                    <div class="col-xs-6 col-sm-6 col-lg-6 col-md-6">
                        <div class="form-group">
                            <ejs-numerictextbox #cardNo format='0' placeholder='Card No' floatLabelType='Auto'
                                [showSpinButton]=false></ejs-numerictextbox>
                        </div>
                    </div>
                    <div class="col-xs-6 col-sm-6 col-lg-6 col-md-6">
                        <div class="form-group">
                            <div class="e-float-input">
                                <input type="text" id="cardHolder" name="cardHolder" required="" #cardHolderRef/>
                                <span class="e-float-line"></span>
                                <label class="e-float-text" for="cardHolder">CardHolder Name</label>
                            </div>
                        </div>
                    </div>
                    <div class="col-xs-6 col-sm-6 col-lg-6 col-md-6">
                        <ejs-datepicker #date width='100%' format='MM/yyyy' placeholder='Expiry Date'
                            floatLabelType='Auto'></ejs-datepicker>
                    </div>
                    <div class="col-xs-6 col-sm-6 col-lg-6 col-md-6">
                        <div class="form-group">
                            <ejs-numerictextbox #cvv format='0' placeholder='CVV' floatLabelType='Auto'
                                [showSpinButton]=false></ejs-numerictextbox>
                        </div>
                    </div>
                    <div style="text-align: center">
                        <button class='e-btn' id="Back_Btn" (click)='btnClick($event)'>Back</button>
                        <button class='e-btn' id="Save_Btn" (click)='btnClick($event)'>Save</button>
                        <div id="err3" #error1>* Please fill all fields</div>
                    </div>
                </div>
            </ng-template>
        </e-accordionitem>
    </e-accordionitems>
</ejs-accordion>
import { Component, ViewChild, OnInit } from '@angular/core';
import { enableRipple, isNullOrUndefined as isNOU } from '@syncfusion/ej2-base';
import { DialogComponent } from '@syncfusion/ej2-angular-popups';
import { DatePicker } from '@syncfusion/ej2-calendars';
import { NumericTextBoxComponent } from '@syncfusion/ej2-angular-inputs';
import { AccordionComponent, AccordionItemsDirective, AccordionItemDirective } from '@syncfusion/ej2-angular-navigations';
import { DatePickerComponent } from '@syncfusion/ej2-angular-calendars';
import { ElementRef } from '@angular/core';

enableRipple(true);

@Component({
  selector: 'app-container',
  templateUrl: './app.component.html'
})

export class AppComponent implements OnInit {
  @ViewChild('alertDlg') alertDlg?: DialogComponent;
  @ViewChild('accordion') accordion?: AccordionComponent;
  @ViewChild('mobile') mobile?: NumericTextBoxComponent;
  @ViewChild('cardNo') cardNo?: NumericTextBoxComponent;
  @ViewChild('date') expiry?: DatePickerComponent;
  @ViewChild('cvv') cvv?: NumericTextBoxComponent;
  @ViewChild('emailRef') emailReference!: ElementRef<HTMLInputElement>;
  @ViewChild('passwordRef') passwordRef!: ElementRef<HTMLInputElement>;
  @ViewChild('nameRef') nameRef!: ElementRef<HTMLInputElement>;
  @ViewChild('addressRef') addressRef!: ElementRef<HTMLInputElement>;
  @ViewChild('cardHolderRef') cardHolderRef!: ElementRef<HTMLInputElement>;
  @ViewChild('error1') error1!: ElementRef<HTMLDivElement>;
  @ViewChild('error2') error2!: ElementRef<HTMLDivElement>;
  @ViewChild('error3') error3!: ElementRef<HTMLDivElement>;

  public dlgTarget?: HTMLElement;
  public dlgButtons?: Object[];
  public success: string = 'Your payment successfully processed';
  public email_alert: string = 'Enter valid email address';
  public mobile_alert: string = 'Mobile number length should be 10';
  public card_alert: string = 'Card number length should be 16';
  public cvv_alert: string = 'CVV number length should be 3';

  public ngOnInit(): void {
    this.dlgTarget = document.body;
    this.dlgButtons = [{
      buttonModel: { content: 'Ok', isPrimary: true },
        click: (() => {
          this.alertDlg?.hide();
          if ((this.accordion as AccordionComponent).expandedIndices[0] === 2 && this.alertDlg?.content === this.success) {
            (this.accordion as AccordionComponent).enableItem(0, true);
            (this.accordion as AccordionComponent).enableItem(1, false);
            (this.accordion as AccordionComponent).enableItem(2, false);
            (this.accordion as AccordionComponent).expandItem(true, 0);
          }
        })
      }];
  }

  public dlgCreated(): void {
    this.alertDlg?.hide();
  }

  public acrdnCreated(): void {
   (this.accordion as AccordionComponent).enableItem(1, false);
   (this.accordion as AccordionComponent).enableItem(2, false);
  }

  public btnClick(e: any): void {
    switch (e.target.id) {
      case 'Continue_Btn':
        let email: string | any = this.emailReference.nativeElement.value;
        let password: string | any = this.passwordRef.nativeElement.value;
        if(email !== '' && password !== '') {
          if(this.checkMail(email)) {
            email = password = '';
            (this.accordion as AccordionComponent).enableItem(1, true);
            (this.accordion as AccordionComponent).enableItem(0, false);
            (this.accordion as AccordionComponent).expandItem(true, 1);
          }
          this.error1.nativeElement.classList.remove('show');
        } else {
          this.error1.nativeElement.classList.add('show');
        }
        break;
      case 'Continue_BtnAdr':
        let name: string | any = this.nameRef.nativeElement.value;
        let address: string | any = this.addressRef.nativeElement.value;
        if((name !== '') && (address !== '') && (!isNOU((this.mobile as NumericTextBoxComponent).value))) {
          if(this.checkMobile((this.mobile as NumericTextBoxComponent).value)) {
            (this.accordion as AccordionComponent).enableItem(2, true);
            (this.accordion as AccordionComponent).enableItem(1, false);
            (this.accordion as AccordionComponent).expandItem(true, 2);
          }
          this.error2.nativeElement.classList.remove('show');
        } else {
          this.error2.nativeElement.classList.add('show');
        }
        break;
      case 'Back_Btn':
        (this.accordion as AccordionComponent).enableItem(1, true);
        (this.accordion as AccordionComponent).enableItem(2, false);
        (this.accordion as AccordionComponent).expandItem(true, 1);
        break;
      case 'Save_Btn':
        let cardHolder: string | any = this.cardHolderRef.nativeElement.value;
        if(!isNOU((this.cardNo as NumericTextBoxComponent).value) && (cardHolder !== '') && (!isNOU((this.expiry as DatePickerComponent).value)) && !isNOU((this.cvv as NumericTextBoxComponent).value)) {
          if (this.checkCardNo((this.cardNo as NumericTextBoxComponent).value)) {
            if (this.checkCVV((this.cvv as NumericTextBoxComponent).value)) {
              (this.alertDlg as DialogComponent).content = this.success;
              (this.alertDlg as DialogComponent).show();
            }
          }
          this.error3.nativeElement.classList.remove('show');
        } else {
          this.error3.nativeElement.classList.add('show');
        }
        break;
    }
  }

  public checkMail(mail: string) {
    if (/^\w+([\.-]?\w+)*@\w+([\.-]?\w+)*(\.\w{2,3})+$/.test(mail)) {
      return true;
    } else {
      (this.alertDlg as DialogComponent).content = this.email_alert;
      (this.alertDlg as DialogComponent).show();
      return false;
    }
  }

  public checkMobile(mobile: number) {
    if (/^\d{10}$/.test(mobile as any)) {
      return true;
    } else {
      (this.alertDlg as DialogComponent).content = this.mobile_alert;
      (this.alertDlg as DialogComponent).show();
      return false;
    }
  }

  public checkCardNo(cardNo: number) {
    if (/^\d{16}$/.test(cardNo as any)) {
      return true;
    } else {
      (this.alertDlg as DialogComponent).content = this.card_alert;
      (this.alertDlg as DialogComponent).show();
      return false;
    }
  }

  public checkCVV(cvv: number) {
    if (/^\d{3}$/.test(cvv as any)) {
      return true;
    } else {
      (this.alertDlg as DialogComponent).content = this.cvv_alert;
      (this.alertDlg as DialogComponent).show();
      return false;
    }
  }
}
import { BrowserModule } from '@angular/platform-browser';
import { NgModule, CUSTOM_ELEMENTS_SCHEMA } from '@angular/core';

import { DialogAllModule } from '@syncfusion/ej2-angular-popups';
import { DatePickerAllModule } from '@syncfusion/ej2-angular-calendars';
import { NumericTextBoxAllModule } from '@syncfusion/ej2-angular-inputs';
import { AccordionModule } from '@syncfusion/ej2-angular-navigations';

import { AppComponent } from './app.component';

/**
 * Module
 */
@NgModule({
    imports: [
        BrowserModule,
        DialogAllModule,
        AccordionModule,
        DatePickerAllModule,
        NumericTextBoxAllModule
    ],
    declarations: [AppComponent],
    bootstrap: [AppComponent]
})
export class AppModule { }
import { platformBrowserDynamic } from '@angular/platform-browser-dynamic';
import { enableProdMode } from '@angular/core';
import { AppModule } from './app.module';

import 'zone.js';
enableProdMode();
platformBrowserDynamic().bootstrapModule(AppModule);