Friday 25 September 2020

Async Await in TypeScript

TypeScript 1.7 now supports async await keywords for asynchronous programming. This makes the codes more readable and simpler than using the older syntax.
If we have this before:
getItems() {
 return new Promise((resolve, reject) => {
   . . .
   resolve(items);
 });
};
Now can be written as:
async getItems() {
 . . .
 // return items; // this will automatically wrap with Promise type
 return Promise.resolve(items);
}
An async function always return Promise type. If there is an object to be returned and not explicitly written with Promise, it will wrap the object.

To run async method synchronously or to wait until it finishes, we use await keywords.
// previous way
getItems()
 .then((items) => {
    print(items);
     . . .
 });
 
// new way
let items = await getItems();
print(items);
Similarly if we would like to run a number of async methods synchronously, like how we used to do that with a chain of .then( . . .), now we do:
let resultOne = await functionOne();
let resultTwo = await functionTwo(resultOne);
let resultThree = await functionThree(resultTwo);

// or if the functions do not return anything
await functionOne();
await functionTwo();
await functionThree();

To handle error, now we use try catch.
getItems() {
   try {
      . . .
      return Promise.resolve(items);
   }
   catch(error) {
      . . .
      return Promise.reject(error_message);
   }
 });
};
Then when we call the function, the returned Promise.reject() will be treated as an error:
try {
   . . .
   getItems();
}
catch(error_message) {
   print(error_message);
}

To run a bunch of async functions without any particular order we use Promise.all():
Promise.all([functionOne(), functionTwo(), functionThree()]);
Promise.all() returns a Promise that has an array of resolved values from each function.

Finally, Promise.race() is used to run a bunch of async functions and return the first one resolves or rejects. It will return a new Promise with the value of the first function finishes.


Further reading:
Keep Your Promises in TypeScript using async/await

Wednesday 12 August 2020

Checking Host Platform in Ionic 5

We can use Platform service in Ionic library to check the host platform. Below are the codes:
import { Platform } from '@ionic/angular';   // first import this library

constructor(private plt: Platform) {
	this.plt.ready().then(() => {

		if (this.plt.is('android') || this.plt.is('ios')) {
			console.log("running on Android or ios device!");

		}

		if (this.plt.is('mobileweb')) {
			console.log("running in a browser on mobile!");
		}
		
		if (this.plt.is('desktop')) {
			console.log("running on desktop");
		}
	});
}
Possible values are (from Ionic website):
Platform Name Description
android a device running Android
capacitor a device running Capacitor
cordova a device running Cordova
desktop a desktop device
electron a desktop device running Electron
hybrid a device running Capacitor or Cordova
ios a device running iOS
ipad an iPad device
iphone an iPhone device
mobile a mobile device
mobileweb a web browser running in a mobile device
phablet a phablet device
pwa a PWA app
tablet a tablet device


Wednesday 8 July 2020

Passing Data from Ionic PopoverController

Since Ionic version 5, Events is no longer supported and will give compilation error. I have posted Using Popover Controller in Ionic but there's a proper way to pass data back from the popover controller to the caller.

We should leverage onDidDismiss() function in the caller component and passing the data as an argument of dismiss() function in the popover.

Caller component create and show popover:
async showCalculateWeeklyRent(ev) {
 const popover = await this.popoverCtrl.create({
  component: CalculateRentComponent, // the popover component that we created
  event: ev,
  componentProps: { 
     // data to be passed
     . . .
  },
  cssClass: 'popoverClass',
 });

 // get data returned from the popover
 popover.onDidDismiss().then(returnedValue => {
  if (returnedValue.data) {   // need to access the 'data' property to get the returned value
   this.model.weeklyRent = returnedValue.data;
   this.calculateYearlyRent();
  }
 });

 return await popover.present();
}
Note that we need to use the data property to get the value.

Then on the popover component, we can simply pass an argument when closing it:
. . .
     
closeAndReturnData() {
    // pass data to caller
    this.popoverCtrl.dismiss(this.shouldBeWeeklyRent);
}

closePopOver() {
    // simply close it
    this.popoverCtrl.dismiss();
}

. . .