loading...
Cover image for How To Declare And Use Ionic Modals With Stencil

How To Declare And Use Ionic Modals With Stencil

daviddalbusco profile image David Dal Busco Originally published at Medium ・5 min read

One Trick A Day (35 Part Series)

1) How To Call The Service Worker From The Web App Context 2) Replace Environment Variables In Your Index.html 3 ... 33 3) Inject JavaScript Or CSS At Runtime And On Demand 4) Sometimes You Just Need A Dumb Library 5) Internationalization with Gatsby 6) How To Declare And Use Ionic Modals With Stencil 7) Get App Name And Version In Angular 8) Deploy Apps And Functions To Firebase From A Mono Repo With GitHub Actions 9) Starting In A New Company? Think Npmrc And Git Name 10) Test Angular Pipes With Services 11) Gatsby Tricks: Viewport, CSS Modules Transition And i18n Tricks 12) Takeover The Cordova Facebook Plugin Maintenance 13) Protect Your HTTP Firebase Cloud Functions 14) Create A Menu For Your Gatsby Website Without Libs 15) Create A Modal For Your Angular App Without Libs 16) Add A Slider To You Angular App 17) Test Angular Components and Services With HTTP Mocks 18) Merge Two Objects And Array To Object In JavaScript 19) JSX For Angular Developers 20) More JSX For Angular Developers 21) Create Your Own NPM Cli 22) Third Party Service Providers. Be transparent to each other! 23) React And Web Workers 24) Angular Testing: Mock Private Functions 25) React, Web Workers and IndexedDB 26) React, Web Workers, IndexedDB and ExcelJS 27) GitHub Actions: Hide And Set Angular Environment Variables 28) JavaScript Useful Functions 29) Deeplinking in Ionic Apps With Branch.io 30) Follow-up: Web Push Notifications And PWA In 2020 31) Angular And Web Workers 32) Git Commands I Always Forget 33) An Open Source Medium Like WYSIWYG Editor 34) Currency Picker And Formatter With Ionic React 35) Develop A Konami Code For Any Apps With Stencil

I am sharing one trick a day until the end of the COVID-19 quarantine in Switzerland, April 19th 2020. Twenty-nine days left until hopefully better days.


This week on Slack, we discussed the usage of Ionic modals in Stencil apps. I shared the solution we have implemented in all applications of DeckDeckGo, our open source editor for presentations, and it seemed to do the trick.

Even though the related Ionic Modal documentation is self explanatory and really well documented, when it comes to vanilla JavaScript or modern frontend frameworks, there isn’t any information regarding the Stencil usage.

That’s why, all in all, I thought I can share an article about this particular subject.


Controllers

Probably the major difference in terms of usage, if you compare to Ionic for React or vanilla Javascript, using Ionic modals in Stencil requires controllers.

For having tested all flavors (except Vue) of Ionic, this is still my favorite solution because I feel more comfortable with, but I’m not sure it will remains like this in the future as, if I understand correctly, many developers including some of the team itself rather like the other solution, without controllers. Therefore, if you read this article in a late future, check first if these still exists or not 😉.


Create A Modal

The modal itself is nothing else than a component. That’s why, if we want to add one to our application, we first create a new component which I rather like to not set as shadowed. Doing so, it will be possible to inherit the CSS properties and style of the application easily.

import {Component, Element, h} from '@stencil/core';

@Component({
  tag: 'app-modal'
})
export class AppRemoteConnect {
  @Element() el: HTMLElement;

  render() {
    return [
      <ion-content class="ion-padding">Hello</ion-content>
    ]
  }

}

Open A Modal

As staten in the introduction, to use modals with Stencil, we are going to use controllers. The trick is to pass the modal tag name as value of the component variable.

import {Component, h} from '@stencil/core';

import {modalController} from '@ionic/core';

@Component({
  tag: 'app-home',
  styleUrl: 'app-home.css'
})
export class AppHome {

  private async openModal() {
    const modal: HTMLIonModalElement =
                 await modalController.create({
      component: 'app-modal'
    });

    await modal.present();
  }

  render() {
    return (
      <ion-content>
        <ion-button onClick={() => this.openModal()}
                    color="primary">
          <ion-label>Open Modal</ion-label>
        </ion-button>
      </ion-content>
    );
  }
}

If everything went according plan, once started and opened, it should looks like the following:


Close A Modal

In this chapter we are going to explore the different ways to close the modal.

Button In Modal Header

To close the modal from itself, we use the document reference to find the closest ion-modal element in order to call the method dismiss which is exposed to achieve such a goal.

import {Component, Element, h} from '@stencil/core';

@Component({
  tag: 'app-modal'
})
export class AppRemoteConnect {
  @Element() el: HTMLElement;

  async closeModal() {
    await (this.el.closest('ion-modal') as 
           HTMLIonModalElement).dismiss();
  }

  render() {
    return [
      <ion-header>
        <ion-toolbar color="secondary">
          <ion-buttons slot="start">
            <ion-button onClick={() => this.closeModal()}>
              <ion-icon name="close"></ion-icon>
            </ion-button>
          </ion-buttons>
        </ion-toolbar>
      </ion-header>,

      <ion-content class="ion-padding">Hello</ion-content>
    ]
  }

}

Again, if everything went fine, a close button in the header should now be displayed.


Hardware Back Button Support

It’s been a while since I didn’t tested the hardware back button support to close the modal on Android but what I generally do is adding a navigation listener, in the modal, which call the same close function as the one we defined before. This hack is based on the history, that’s why a state has to be pushed when the modal is loaded.

import {Listen} from '@stencil/core';

async componentDidLoad() {
  history.pushState({modal: true}, null);
}

@Listen('popstate', {target: 'window'})
async handleHardwareBackButton(_e: PopStateEvent) {
  await this.closeModal();
}

Backdrop Dismiss

Per default, modals can be dismissed through a click on their backdrops. If you wish to disable this option, you have to specify it when at the controller level.

const modal: HTMLIonModalElement = await modalController.create({
  component: 'app-modal',
  backdropDismiss: false
});

Passing Parameters

In this chapter we are passing parameters from the page to the modal and in the other direction.

Page To Modal

This is probably my favorite thing across all flavors of Ionic modals I tried. Passing parameters with Stencil is super duper easy.

To read parameters in the modals, we only have to define properties (@Prop()).

import {Component, Element, h, Listen, Prop} from '@stencil/core';

@Component({
  tag: 'app-modal'
})
export class AppRemoteConnect {
  @Element() el: HTMLElement;

  @Prop()
  greetings: string;

  @Listen('popstate', {target: 'window'})
  async handleHardwareBackButton(_e: PopStateEvent) {
    await this.closeModal();
  }

  async closeModal() {
    await (this.el.closest('ion-modal')
           as HTMLIonModalElement).dismiss();
  }

  render() {
    return [
      <ion-header>
        <ion-toolbar color="secondary">
          <ion-buttons slot="start">
            <ion-button onClick={() => this.closeModal()}>
              <ion-icon name="close"></ion-icon>
            </ion-button>
          </ion-buttons>
        </ion-toolbar>
      </ion-header>,

      <ion-content class="ion-padding">
           {this.greetings}
      </ion-content>
    ]
  }

}

Which we then just pass through the controllers.

private async openModal() {
  const modal: HTMLIonModalElement = await modalController.create({
    component: 'app-modal',
    backdropDismiss: false,
    componentProps: {
      greetings: 'Yolo'
    }
  });

  await modal.present();
}

Nothing more, nothing left, really easy. I like such solution.


Modal To Page

You might need to pass results from the modal to the page or calling components. To do so, we use the function dismiss , as when did to close the modal, but we pass an object as parameter.

async closeModalWithParams(greetings: string) {
  await (this.el.closest('ion-modal')
        as HTMLIonModalElement).dismiss(greetings);
}

<ion-button onClick={() => this.closeModalWithParams('Hello')}>
     Say Hello!
</ion-button>

In our example, I linked this new action with a new button.

Finally, to handle the result, we listen to the onDidDismiss event of the modal and proceed with the details passed as callback.

import {Component, h, State} from '@stencil/core';

import {modalController, OverlayEventDetail} from '@ionic/core';

@Component({
  tag: 'app-home',
  styleUrl: 'app-home.css'
})
export class AppHome {

  @State()
  private greetingsResult: string;

  private async openModal() {
    const modal: HTMLIonModalElement =
                 await modalController.create({
      component: 'app-modal',
      backdropDismiss: false,
      componentProps: {
        greetings: 'Yolo'
      }
    });

    modal.onDidDismiss().then(
          async (detail: OverlayEventDetail) => {
      this.greetingsResult = detail.data;
    });

    await modal.present();
  }

  render() {
    return (
      <ion-content>
        <ion-button onClick={() => this.openModal()} 
                    color="primary">
          <ion-label>Open Modal</ion-label>
        </ion-button>

        <ion-label>{this.greetingsResult}</ion-label>
      </ion-content>
    );
  }
}

I used a state as demonstration purpose in order to render the results.

Note that you can use both primitives types, complex objects, callbacks or events as parameters.


Cherry On The Cake

It works exactly the same with popovers.


See It In Action

If you are interested to see Ionic modals used in Stencil apps in action, give a try to DeckDeckGo for your next slides 😁.

Stay home, stay safe!

David

Cover photo by Tirza van Dijk on Unsplash

One Trick A Day (35 Part Series)

1) How To Call The Service Worker From The Web App Context 2) Replace Environment Variables In Your Index.html 3 ... 33 3) Inject JavaScript Or CSS At Runtime And On Demand 4) Sometimes You Just Need A Dumb Library 5) Internationalization with Gatsby 6) How To Declare And Use Ionic Modals With Stencil 7) Get App Name And Version In Angular 8) Deploy Apps And Functions To Firebase From A Mono Repo With GitHub Actions 9) Starting In A New Company? Think Npmrc And Git Name 10) Test Angular Pipes With Services 11) Gatsby Tricks: Viewport, CSS Modules Transition And i18n Tricks 12) Takeover The Cordova Facebook Plugin Maintenance 13) Protect Your HTTP Firebase Cloud Functions 14) Create A Menu For Your Gatsby Website Without Libs 15) Create A Modal For Your Angular App Without Libs 16) Add A Slider To You Angular App 17) Test Angular Components and Services With HTTP Mocks 18) Merge Two Objects And Array To Object In JavaScript 19) JSX For Angular Developers 20) More JSX For Angular Developers 21) Create Your Own NPM Cli 22) Third Party Service Providers. Be transparent to each other! 23) React And Web Workers 24) Angular Testing: Mock Private Functions 25) React, Web Workers and IndexedDB 26) React, Web Workers, IndexedDB and ExcelJS 27) GitHub Actions: Hide And Set Angular Environment Variables 28) JavaScript Useful Functions 29) Deeplinking in Ionic Apps With Branch.io 30) Follow-up: Web Push Notifications And PWA In 2020 31) Angular And Web Workers 32) Git Commands I Always Forget 33) An Open Source Medium Like WYSIWYG Editor 34) Currency Picker And Formatter With Ionic React 35) Develop A Konami Code For Any Apps With Stencil

Posted on by:

daviddalbusco profile

David Dal Busco

@daviddalbusco

Creator of DeckDeckGo | Organizer of the Ionic Zürich Meetup

Discussion

markdown guide