Search code examples
angulartypescriptionic-frameworkmodal-dialogionic6

how can i reuse the same modal in ionic?


sorry about the title I wasn't sure how to phrase this question, But my issue is that I have a list of clickable elements and I want to pass their data to a single modal instead of creating modals for each list element? so for example i click on item 1 and its data is displayed inside the modal, after i close the modal i click on item 2 and its data is displayed using the same modal. I looked through the ionic docs but I couldn't find anything similar to this there, I tried changing the id that the modal uses to trigger it opening to a class but that didn't work, would anyone have any pointers for my issue?

thanks in advance!

list-details.component.html

<ion-list>
     <ng-container *ngFor="let item of myList">
      <ion-item detail="true">
        <ion-button id="open-modal" expand="block" (click)="getItem(item)">
          <ion-label>
            <h2 class="headline">{{item.beer}}</h2>
            <h3 class="sub-headline">{{item.name}}</h3>
            <p>{{item.notes}}</p>
            <p>{{item.price | currency}}</p>
            <app-rating [rating]="item.rating"></app-rating>
          </ion-label>
        </ion-button>
      </ion-item>
      </ng-container>
    </ion-list>
    
    <ion-modal trigger="open-modal" (willDismiss)="onWillDismiss($event)">
      <ng-template>
        <ion-header>
          <ion-toolbar>
            <ion-buttons slot="start">
              <ion-button (click)="cancel()">Cancel</ion-button>
            </ion-buttons>
            <ion-title>{{user.name}}</ion-title>
            <ion-buttons slot="end">
              <ion-button (click)="confirm()" [strong]="true">Confirm</ion-button>
            </ion-buttons>
          </ion-toolbar>
        </ion-header>
        <ion-content class="ion-padding">
          <ion-item>
            <ion-label position="stacked">Enter your name</ion-label>
            <ion-input type="text" placeholder="Your name" [(ngModel)]="name"></ion-input>
          </ion-item>
        </ion-content>
      </ng-template>
    </ion-modal>

list-details.component.ts

    export class ListDetailsComponent implements OnInit {
  @ViewChild(IonModal) modal: IonModal;
  
  message = 'This modal example uses triggers to automatically open a modal when the button is clicked.';
  name: string;
  user: any;

  constructor() { }

  ngOnInit() {
  }

  

  getItem(item: any){
    this.user = item;
  }
  cancel() {
    this.modal.dismiss(null, 'cancel');
  }

  confirm() {
    this.modal.dismiss(this.name, 'confirm');
  }

  onWillDismiss(event: Event) {
    const ev = event as CustomEvent<OverlayEventDetail<string>>;
    if (ev.detail.role === 'confirm') {
      this.message = `Hello, ${ev.detail.data}!`;
    }
  }

}

Solution

  • With the modalController developers can present an ion-modal programmatically. Developers will have complete control over when a modal is presented and dismissed.

    app.component.html

    <ion-app>
      <ion-content>
        <hello name="{{ name }}"></hello>
        <p>Dynamic Data with Ionic Modal Example</p>
    
        <ng-container *ngFor="let data of listData">
          <ion-item href="#" (click)="openIonModal(data)">
            <ion-label>{{ data.name }}</ion-label>
          </ion-item>
        </ng-container>
      </ion-content>
    </ion-app>
    

    app.component.ts

    import { Component, VERSION } from '@angular/core';
    import { ModalController } from '@ionic/angular';
    import { CustomModalComponent } from '../custom-modal/custom-modal.component';
    
    export interface ListData {
      id: number;
      name: string;
    }
    
    @Component({
      selector: 'my-app',
      templateUrl: './app.component.html',
      styleUrls: ['./app.component.css'],
    })
    export class AppComponent {
      name = 'Ionic 6.2 Angular ' + VERSION.major;
    
      listData: ListData[] = [
        {
          id: 1,
          name: 'Test 1',
        },
        {
          id: 2,
          name: 'Test 2',
        },
        {
          id: 3,
          name: 'Test 3',
        },
      ];
    
      modelData: any;
    
      constructor(private _modalController: ModalController) {}
    
      ionViewDidEnter() {}
    
      async openIonModal(data: ListData) {
        const modal = await this._modalController.create({
          component: CustomModalComponent,
          componentProps: {
            modelTitle: data.name,
          },
        });
        modal.onDidDismiss().then((modelData) => {
          if (modelData !== null) {
            this.modelData = modelData.data;
            console.log('Modal Data : ' + modelData.data);
          }
        });
        return await modal.present();
      }
    }
    

    custom-modal.component.ts

    import { Component, Input, OnInit } from '@angular/core';
    import { ModalController } from '@ionic/angular';
    
    @Component({
      selector: 'app-custom-modal',
      templateUrl: './custom-modal.component.html',
      styleUrls: ['./custom-modal.component.css'],
    })
    export class CustomModalComponent implements OnInit {
      @Input() modelTitle: string;
    
      constructor(private _modalController: ModalController) {}
    
      ngOnInit() {}
    
      async closeModel() {
        const close: string = 'Modal Removed';
        await this._modalController.dismiss(close);
      }
    }
    

    custom-modal.component.html

    <ion-header>
      <ion-toolbar>
        <ion-title>Ionic Modal Popup Example</ion-title>
      </ion-toolbar>
    </ion-header>
    <ion-content>
      <ion-grid>
        <ion-row>
          <ion-col text-center> Model Title : {{ modelTitle }} </ion-col>
        </ion-row>
        <ion-row>
          <ion-col text-center>
            <ion-button (click)="closeModel()">Close</ion-button>
          </ion-col>
        </ion-row>
      </ion-grid>
    </ion-content>
    

    Working example is here