Monday, May 11, 2020

ionic layout related css styles

1. Relative layout attribute 
The first kind of layout css styles for ionic (or html) are used to specify where to put the current element to its parents' space, including:
slot attribute for ion-item element,
float attribute of ion-float-left, ion-float-right, etc

The second kind of layout css styles are used to specify where its children elements and the element itself 's content should be put in its own space, including:
text align attributes of ion-text-start, and ion-text-center, etc
Flex container horizontal attribute of ion-justify-content-start, ion-justify-content-center, etc. (applied to ion-row for grid)
Flex container vertical attribute of ion-align-self-start, ion-align-self-center (applied to ion-row for grid)
ion-padding (applied to ion-grid for grid)
ion-margin (applied to ion-grid for grid )

2. Difference between ion-spinner and LoadingController 
Both ion-spinner and LoadingController can be used to show a busy spinner on html page to indicate the current task is busy. The difference is ion-spinner is just a html element of busy cursor shown on the screen, and it does not affect or block other html element's function. So user can still click a button to execute its handler.
On the contrary, when LoadingController is created and present on the screen, it shows the busy cursor as well as other message on an overlay of the current html page, similar to showing a modal dialog box on native apps, so all other UI elements are disabled by default, and user cannot click a button or link to continue.

Html code:
  <ion-button (click)="onLogin()"> Login
  </ion-button>
  <ion-button (click)="onLogin(true)"> Login Direct
  </ion-button>
  <ion-button (click)="onLoginByController()"> Login By Controller
  </ion-button>
  <div class="ion-text-center">
    <ion-spinner color="primary" *ngIf="isLoading"></ion-spinner>
  </div>

ts code:
  onLogin(b) {
    this.isLoading = true;
    console.log('login clicked');
    if (b) {
      this.isLoading = false;
      this.authService.login();
    } else {
      setTimeout(() => {
        this.isLoading = false;
        this.authService.login();
      }, 10000);
    }
  }

  onLoginByController() {
    this.loadingCtrl.create({keyboardClose: true, message: 'Logging in...'}).then(loadingEl => {
      loadingEl.present();
      setTimeout(() => {
        this.authService.login();
      }, 10000);
    });
  }

Saturday, May 2, 2020

ionic side drawer or hamburger menu support

ion-menu can be used to support side drawer or hamburger menu on ios and android devices. There are some notes to use the ion-menu function.

ion-menu usually are defined in app component html file, and they are identified by menuId attribute. If multiple ion-menu elements are configured, then only the last one is enabled.
 <ion-menu side="start" contentId="main" menuId="menu1" disabled="false">
    <ion-header>
      <ion-toolbar>
        <ion-title>Menu 1</ion-title>
      </ion-toolbar>
    </ion-header>
    <ion-content>
       <ion-list lines="none">
      <ion-menu-toggle>
        <ion-item routerLink="/places/search">
          <ion-icon name="business" slot="start"></ion-icon>
          <ion-label>Search Places</ion-label>
        </ion-item>
      </ion-menu-toggle>
      <ion-menu-toggle>
        <ion-item routerLink="/places/offers">
          <ion-icon name="checkbox-outline" slot="start">
          </ion-icon>
          <ion-label>Your Booking</ion-label>
        </ion-item>
      </ion-menu-toggle>
      <ion-menu-toggle>
        <ion-item (click)="onExit()" button>
          <ion-icon name="exit" slot="start">
          </ion-icon>
          <ion-label>Logout</ion-label>
        </ion-item>
      </ion-menu-toggle>
      </ion-list>
    </ion-content>
  </ion-menu>

In ion-pages, it can use ion-menu-button to show a side drawer or hamburger menu icon using ion-menu-button element as below. The menu attribute indicates which menu element (menu2 in this case) will show when user clicks the side drawer menu icon
<ion-header>
  <ion-toolbar>
    <ion-title>My Offers</ion-title>
    <ion-buttons slot="start">
      <ion-menu-button menu="menu2"></ion-menu-button>
    </ion-buttons>
    <ion-buttons slot="primary">
      <ion-button routerLink="/places/offers/new">
          <ion-icon name="add" slot="icon-only"></ion-icon>
      </ion-button>
    </ion-buttons>
  </ion-toolbar>
</ion-header>

However, in order to show the side drawer or hamburger menu icon on the page toolbar, the specified menu element must be enabled. An easy way to do so it enable it by calling the MenuController's enabled method as below. When enabling a menu element, all other menu elements will be automatically disabled.


  constructor(private menuCtrl: MenuController) { }


  ngOnInit() {
    this.menuCtrl.enable(true, 'menu2');
  }

In case needed, you can also use the below method to query all available menu element's status. 
      const m  = await this.menuCtrl.getMenus();
      m.forEach(el => {
        console.log(el.menuId);
        el.isOpen().then(d => {console.log('isOpen in loop: ', d); });
        console.log( 'isDisabled in loop: ', el.disabled);
      });

Note javascript await cannot be used inside forEach method, so then method is used to log the async method isOpen's result. Otherwise, using await is a better option to log the result synchronously when handling promise as return value as below
      console.log('menu 1 is Open', await this.menuCtrl.isOpen(el.menuId));
      console.log('menu1 is disabled', await this.menuCtrl.isEnabled(el.menuId));

When a menu item is clicked and handled, the menu will not close automatically. To close the menu automatically, the ion-item needs to be wrapped inside an ion-menu-toggle element. The ionic document is not very helpful in many cases.