Author: Chris Griffith

Besides my passion for space flight, I am an avid hiker and sea kayaker. I am also a technical author, mobile developer and work as a user experience designer/developer.

AngularFire Update: Ionic Book

One of the challenges in writing a technical book is that the content can become outdated as the software undergoes updates. Hence, why we had to release a revised edition of Mobile Apps with Ionic. Recently, AngularFire had an update that affected the sample To-Do app in Chapter 7. This post is going to walk you through the changes. The code has been updated to the GitHub repo.

One first changes you need to make is what you install from npm. In the book, I have you run this command:

$ npm install angularfire2 firebase –save

However, we need to now install one more package, promise-polyfill in order to properly build our application. The new command is:

$ npm install angularfire2 firebase promise-polyfill –save

The first set of changes we need to make is in the app.module.ts file. The capabilities of Firebase (and AngularFire) are growing, as such, they are breaking each of the features into smaller modules. By doing so, our code base only has the elements it needs. No need to have FireBase Auth in our code if we aren’t using it. Our AngularFire imports should now look like this;

import { AngularFireModule } from 'angularfire2';
import { AngularFireDatabaseModule, AngularFireDatabase } from 'angularfire2/database';

We still need to define our apikey, domains, etc in the config object and pass that into the AngularFireModule.initializeApp(firebaseConfig)

We now also need to add AngularFireDatabaseModule  in our imports array as well.

The final item to change is the providers array, you now need to include AngularFireDatabase.

Turning to the tasklist.ts file, we have several items to modify. We now have several new imports:

import { AngularFireDatabase, AngularFireList } from 'angularfire2/database';
import { Observable } from 'rxjs/Observable';

The first brings in the AngularFireDatabase and AngularFireList modules. One of the major changes with AngularFire 5, was moving anay from custom types to more generic types. Hence, why the second import of the Observable package from rxjs.

Next we need to change our variables and their types:

taskList: AngularFireList<Task>;
tasks: Observable<any[]>;

The taskList variable will hold the AngularFire data in its ‘native’ form, while the task variable will have a clean version of the data that our template can reference.

In the constructor, we define the values for both of these variables:

this.taskList = this.af.list('/tasks');
this.tasks = this.taskList.valueChanges();

First, we get the list of to-dos from our Firebase database, and assign that to the tasklist. Next, we call the valueChanges method on the taskList. From the AngularFire docs; it returns an Observable of data as a synchronized array of JSON objects. All Snapshot metadata is stripped and just the method provides only the data.

There are several other data methods available, and you should take the time to review them when you begin working with AngularFire in earnest.

With our data now in different variables, we need to adjust our add, delete, and update calls. Let’s change the add code first. If you grab the source code from GithUb, you will see I have added support for either the native Dialog, as well as the Ionic Alert Controller. The two lines that matter are these:

const newTaskRef = this.taskList.push({ id: '', title: data.task, status: 'open' });
newTaskRef.update({ id: newTaskRef.key});

One of the other changes in AngularFire 5, is moving away from being so key-based. As such we need to store the key within our record now. The actual method to add a record to Firebase is still the same push(). But now we get the result of that action, then immediately update itself with the generated id.

Next, we can adjust the markAsDone function. Migrating from the $key code, our new code is simply:

markAsDone(slidingItem: ItemSliding, task: Task) {
    task.status = 'done';
    this.taskList.update(task.id, task)
    slidingItem.close();
}

Our final method to change is the removeTask function. The code is now:

removeTask(slidingItem: ItemSliding, task: Task) {
    this.taskList.remove(task.id);
    slidingItem.close();
}

The final tweak is to our interface definition for the task. We need to support this new id attribute, so it now becomes:

export interface Task {
  title: string;
  status: string;
  id:string
}

Hope this short post, gets you back on track working with Ionic and Angularfire/Firebase.

 

 

 

 

Advertisements

Electron: From Beginner to Pro Released!

 

electron-sign

Your two crazy co-authors! (Photo Credit: Rachel Luxemburg)

 

 

I am pleased to announce that my latest book, Electron: From Beginner to Pro has been released! This time around I enlisted the help of a good friend, Leif Wells to be my co-author on this endeavor. We took a slightly different approach to writing this book. Instead of having the reader create some app(s) that they have no interest in, we focused directly on the features of Electron. This also let us avoid having to either pick a framework like Angular, Vue or React, and exclude some readers.

Ionic App Generator

I am happy to announce the release of a new utility for generating Ionic-based applications, Ionic App Generator (macOS and Windows). The goal of this app is to allow you to completely configure all the aspects of a new Ionic application through one single appliction.

Ionic Generator-1

The general screen exposes the main settings of the Ionic CLI’s start command.

Beyond the general settings, you can also define the manifest.json file used by Progressive Web Apps.

Ionic Generator-2

PWA’s manifest.json screen

Leveraging my experience in writing ConfiGAP, I exposed some of the key settings within the config.xml for Cordova applications.

Ionic Generator-3

Config.xml editor

The full collection of Ionic Native plugins are available to be installed in your application as well.

Ionic Generator-5

Once you have configured your application’s settings, just click the generate app button, and the tool will go through the process of generating the app.

This app is built on Electron and use Ionic for its user interface (of course). I will be writing up some discoveries I learned while building this utility shortly.

You can download it for both macOS and Windows.

Enjoy!

Case Study: Stone Fest 21 – PWA

Living in San Diego, we are surrounded by over 140 craft breweries. Once a year, Stone Brewing hosts an annual celebration, where they invite a bunch of their brewery friends to town and showcase their brews. I have been attending for a number of years, and one of the challenges in attending was having to find the beer on Untappd and check-in. So this year I thought I would whip up a quick Progressive Web App (PWA), that would allow me to quickly locate my beer and check in. Here is a link to the working Stone Fest 21 app.

After assembling the data set of the breweries, the beers, their logos (thanks, Untappd!), I generated the actual Ionic application. Since my buddies were on both iOS and Android, I knew the web was my only publishing option. But before I uploaded the code from Ionic to my server, there were some additional steps required to improve the performance of the PWA. Here is a list of the changes I made to project:

Enable gzip

By default, my Dreamhost account that I hosted Stone Fest 21 on did not have this enabled. So, I had to create a .htaccess file and enable it on the server.

# BEGIN GZIP
< ifmodule mod_deflate.c>
AddOutputFilterByType DEFLATE text/text text/html text/plain text/xml text/css application/x-javascript application/javascript
< /ifmodule>
# END GZIP

Improving iOS support

Since PWA support on iOS is not on par with Android was to include some Apple specific meta tags in the head of the index.html file:

< meta name="apple-mobile-web-app-capable" content="yes">
< meta name="apple-mobile-web-app-status-bar-style" content="black">
< meta name="apple-mobile-web-app-title" content="Stone Fest 21">

For more on these tags, see the Apple documentation.

App Icons

Although the manifest.json defines our app icon, not all platform understand this. So as a backup, I add this snippet in the index.html file to assist with that issue:

< link rel="apple-touch-icon" sizes="57x57" href="apple-icon-57x57.png">
< link rel="apple-touch-icon" sizes="60x60" href="apple-icon-60x60.png">
< link rel="apple-touch-icon" sizes="72x72" href="apple-icon-72x72.png">
< link rel="apple-touch-icon" sizes="76x76" href="apple-icon-76x76.png">
< link rel="apple-touch-icon" sizes="114x114" href="apple-icon-114x114.png">
< link rel="apple-touch-icon" sizes="120x120" href="apple-icon-120x120.png">
< link rel="apple-touch-icon" sizes="144x144" href="apple-icon-144x144.png">
< link rel="apple-touch-icon" sizes="152x152" href="apple-icon-152x152.png">
< link rel="apple-touch-icon" sizes="180x180" href="apple-icon-180x180.png">

I used the $ ionic cordova resources command to generate them, then renamed the manually. Since the $ ionic build command will wipe out the www directory, I added them directly to the server.

Updating the BODY tag

One of the items that the Lighthouse test measures is “First Meaningful Paint”. For those who don’t know this term, First Meaningful Paint is the time when page’s primary content appeared on the screen. I added inline CSS to the body tag, so that the browser would render something while the app was starting.

< body style="background-color: #1c1b17; background-image: url('assets/imgs/logo.jpg'); background-position: center; background-repeat: no-repeat;">

Handling the no JavaScript case

Lighthouse also checks what you do if JavaScript was disabled by the user. Remember, this is a Progressive web app. In my case, there was not a lot you can do without JavaScript, but I included this tag to meet the requirement:

< noscript>
< h1>Stone Fest 21 requires JavaScript< /h1>
< /noscript>

Removing Cordova

When you generate an Ionic application, Cordova plugins are automatically integrated, specifically the Splash Screen and Status Bar plugins. Since we are deploying to the web, we can remove Cordova and these plugins from our project. Using $ npm uninstall @ionic-native/splash-screen and $ npm uninstall @ionic-native/status-bar

Edit the app.module.ts to remove the import statements for these two plugins and remove them from the providers array.

In the app.component.ts file also remove the imports. Also, you will remove the injected imports from the arguments in the constructor, as well as the two references to the plugins in the platform.ready check.

If you generated your Ionic application with Cordova integration, there are other plugins and modules that you should remove as well. If you open your package.json file you will several references to cordova-* items. Go ahead and use npm to uninstall them:

  • cordova-plugin-console
  • cordova-plugin-device
  • cordova-plugin-splashscreen
  • cordova-plugin-statusbar
  • cordova-plugin-whitelist
  • and ionic-plugin-keyboard

Depending on what platforms you may have installed, you might also have these modules:

  • cordova-ios
  • cordova-android

Remove them as well.

Finally, we can also remove @ionic-native/core, as we have now scrubbed our Ionic application of any Ionic Native code.

Image Paths

As I checked my Lighthouse score, I noticed that it was flagging how my brewery logos were being called, as well as an accessibility issue around them. To quickly solve this, I adjusted the img tag to reference the full path to the logo and added the alt attribute

< img src="https://aj-software.com/apps/stone/assets/breweries/{{brewery.logo}}" alt="Company Logo">

Enabling the Serviceworker.js code

By default, this code block is commented out in the index.html. Uncomment this block of code and you have a nicely configured service worker ready to go.

if ('serviceWorker' in navigator) {
 navigator.serviceWorker.register('service-worker.js')
 .then(() => console.log('service worker installed'))
 .catch(err => console.error('Error', err));
}

Updating the manifest.json file

The last tweak is updating some of the items in the default manifest.json file.

  1. Update the name and short name. Note: the short name should not be more than 12 characters in length.
  2. Ensure there is an icon available in the proper directory and of the proper size.
  3. Update the theme and background colors to something that matched our app.
  4. Add an orientation value of portrait
{
 "name": "Stone Fest 21",
 "short_name": "Stone Fest",
 "start_url": "index.html",
 "display": "standalone",
 "icons": [{
 "src": "assets/imgs/logo.jpg",
 "sizes": "512x512",
 "type": "image/jpg"
 }],
 "background_color": "#1c1b17",
 "theme_color": "#1c1b17",
 "orientation": "portrait"
}

Summary

After implementing these steps, the Stone Fest 21 app received  the following Lighthouse score:

pwa_score

Hopefully, these guidelines can help you create better PWA using Ionic. Until stencil.js is ready, this is about a good as I can make an Ionic-Angular’s performance. I will be porting this application to stencil shortly and will update this post with the results. The source code is available on my GitHub account.

Customizing Ionic Native Mocks

By design, the Ionic Native Mocks I wrote are very generic. They just return the bare minimum amount of data for them to function. But for them to be more useful in your project, you probably will want to customize them. In this blog post, I will show you how to do this. For this example, we will customize the BarcodeScanner mock, in part, as it is was the plugin that inspired the project.

In your existing Ionic project, first import the actual Ionic native module:

$ npm install --save @ionic-native/barcode-scanner

And the actual Cordova plugin as well,

$ ionic cordova plugin add phonegap-plugin-barcodescanner

Before we update the app.module.ts file, let’s install the mock first. Although the mocks are available via npm, we want to get the code directly from GitHub and the source typescript code (https://github.com/chrisgriffith/ionic-native-mocks/tree/master/src/%40ionic-native-mocks/plugins/barcode-scanner).

In your project, create a new directory named mocks, and create another directory named barcodescanner. Within that directory, download the index.ts file from Github into this directory.

Now let’s adjust out app.module.ts file. Like all Ionic Native modules, we need to import it.

import { BarcodeScanner } from '@ionic-native/barcode-scanner';

Also import our plugin mock as well.

import { BarcodeScannerMock } from '../mocks/barcodescanner';

Instead of including the Ionic Native plugin directly into the providers array, we instead tell Angular to provide a mapping to our mock. This allows us to keep the rest of application referencing the real Ionic Native module, yet use the code from the mock instead.

{ provide: BarcodeScanner, useClass: BarcodeScannerMock }

At this point we could build our app, making calls to the barcode scanner plugin without needing to install on an actual device. But, out of the box, the barcode scanner is going to return an empty string.

But, let’s have it return something that we might want our user to scan. For my original app, it was a QR code on our packaging. Open the index.ts file within our project and change the scan function to

scan(options?: BarcodeScannerOptions): Promise {

  let code='Your Custom Response Here';

  let theResult:BarcodeScanResult= {format:'QR_CODE', cancelled:false, text:code };

  return new Promise((resolve, reject) => {

    resolve(theResult);

  });

}

Save the file, and run the application. Now when you call the barcode scanner, it will return your custom data.

When you are ready to use the real plugin, change the provider and remove the import of the mock. And there you have a basic guide to customizing your Ionic Native Mocks.