Adding local notifications to an Ionic framework mobile app

January 9, 2018, 9:00 am Categories:

Categories

Over the course of the following tutorial we're going to be developing a simple application that allows a user to generate custom local notifications that can be published to their own handheld device at a date/time of their choosing.

We'll be using the Ionic Native Date Picker and Local Notifications plugins to accomplish this.

By the end of the tutorial we should see something like the following (demonstrated on an iPhone and your content will no doubt vary from mine!) application in use:

Creating local notifications, using a date picker component and granting permissions for the application to receive notifications

Once a local notification has been created and scheduled for publishing the user will receive an alert message informing them that all was successful (first screen capture below).

This is then followed by the local notification being displayed (second screen capture below) and, after the user has tapped on the notification, an alert message will be triggered displaying their message (final screen capture below).

Local notifications and alert messages being displayed on an iPhone device

Now we know what we're developing let's get started...

Initial steps

Open your system CLI software, navigate to where you would normally create/save your digital projects and run the following command to create an Ionic application named ionic-notify:

ionic start ionic-notify blank

We'll need to install the necessary mobile platforms (iOS & Android) as well as the following plugins (and their respective node packages) to provide the date/time selection and local notification functionality for the project:

cd ./ionic-notify
ionic cordova platform add ios
ionic cordova platform add android
ionic cordova plugin add cordova-plugin-datepicker
npm install --save @ionic-native/date-picker
ionic cordova plugin add cordova-plugin-local-notification
npm install --save @ionic-native/local-notifications

One potential gotcha

I experienced an issue with the Ionic Native Local Notifications plugin throwing the following error when running on an iOS device:

Unknown property: at

IF you experience the same issue then use the Ionic CLI to implement the following steps (pay attention to the version number appended to the plugin):

ionic cordova plugin rm cordova-plugin-local-notification
ionic cordova plugin add de.appplant.cordova.plugin.local-notification@0.8.5

This should now resolve that issue and allow you to use the plugin without any further errors.

Rooting the application

With our plugins and their associated node packages installed we next need to turn our attention to the application's root module and ensure that this is configured with the necessary imports.

Open the ionic-notify/src/app/app.module.ts file and configure this so that it resembles the following:

import { BrowserModule } from '@angular/platform-browser';
import { ErrorHandler, NgModule } from '@angular/core';
import { IonicApp, IonicErrorHandler, IonicModule } from 'ionic-angular';
import { SplashScreen } from '@ionic-native/splash-screen';
import { StatusBar } from '@ionic-native/status-bar';
import { DatePicker } from '@ionic-native/date-picker';
import { LocalNotifications } from '@ionic-native/local-notifications';

import { MyApp } from './app.component';
import { HomePage } from '../pages/home/home';

@NgModule({
  declarations: [
    MyApp,
    HomePage
  ],
  imports: [
    BrowserModule,
    IonicModule.forRoot(MyApp)
  ],
  bootstrap: [IonicApp],
  entryComponents: [
    MyApp,
    HomePage
  ],
  providers: [
    StatusBar,
    SplashScreen,
    DatePicker,
    LocalNotifications,
    {provide: ErrorHandler, useClass: IonicErrorHandler}
  ]
})
export class AppModule {}

Adding local notifications

With the plugins/packages installed and the root module configured let's look over the functionality that we'll be implementing within the ionic-notify/src/pages/home/home.ts component class of the ionic-notify application:

  • Creating and scheduling local notifications
  • Select date/time for publishing a local notification
  • Offering the ability to cancel a scheduled notification
  • Providing user feedback courtesy of the Ionic AlertController component

We begin by importing the necessary components and packages:

import { Component } from '@angular/core';
import { AlertController, NavController, Platform } from 'ionic-angular';
import { FormBuilder, FormGroup, Validators } from '@angular/forms'; 
import { DatePicker } from '@ionic-native/date-picker';
import { LocalNotifications } from '@ionic-native/local-notifications';

Within the class itself we then define the necessary properties which we'll use to handle data and manage the visibility of the cancel notification button within the component template:

/**
 * @name form 
 * @type {FormGroup} 
 * @public
 * @description        References a FormGroup object for use
                       with form validation/management
 */
public form                  : FormGroup;



/**
 * @name notification 
 * @type {String} 
 * @public
 * @description        Stores the title for the local notification 
 */
public notification : string;



/**
 * @name summary 
 * @type {String} 
 * @public
 * @description        Stores the message supplied by the local notification 
 */
public summary : string;




/**
 * @name published 
 * @type {String} 
 * @public
 * @description        Stores the published date supplied for the local notification 
*/
public published : any;



/**
 * @name notificationExists 
 * @type {Boolean} 
 * @public
 * @description        Determines whether a notification has been scheduled or not 
 */
public notificationExists : boolean   = false;

Within the class constructor we then define the FormBuilder object for managing the form validation and field data:

// Initialise component/plugin modules
constructor(public navCtrl   : NavController,
  	        private _ALERT   : AlertController,
  	        private _FB      : FormBuilder,
  	        private _DATE    : DatePicker,
  	        private _LOCAL   : LocalNotifications,
  	        private _PLAT    : Platform) 
{
   // Set up form validation - VERY basic
   this.form 		= 	this._FB.group({
      'notification'   : ['', Validators.required],
      'summary'        : ['', Validators.required],
      'published'      : ['', Validators.required]
   });
}

Next we'll make use of the ionViewDidLoad lifecycle event to assign a click event listener for our scheduled local notification(s).

This will enable the user to tap each displayed notification and be subsequently greeted by an alert box containing a custom message (courtesy of the displayAlert method - which we'll come to shortly):

/**
 * Register click event for Local Notifications on view load 
 *
 * @public
 * @method ionViewDidLoad
 * @return {None}
 */
ionViewDidLoad() : void
{
   // Trigger notification event listener ONLY when the 
   // platform is detected/fully initialised
   this._PLAT
   .ready()
   .then(() =>
   {

      // Register click event listener for each local notification
      this._LOCAL.on('click', (notification, state) =>
      {
         var title 	 	=	notification.title,
             message  		= 	JSON.parse(notification.data);

         // Display the supplied message to the user
         this.displayAlert(title, message.message);


         // Now hide the Cancel notification button from view
         if(this.notificationExists)
         {
            this.notificationExists = false;
         }

      });

   });
}

Following from this we then create a scheduleNotification method which will be used to generate the local notification that we want to display to the end user:

/**
 * Schedule a Local Notification and inform the user of success/failure
 *
 * @public
 * @method scheduleNotification
 * @param notification  	{String} 		The text for the local notification
 * @param message  			{String} 		The message to be displayed once the local notification has been clicked on
 * @param published  		{String} 		The date/time when the local notification will be published
 * @return {None}
 */
scheduleNotification(notification 	: string, 
 			         message 		: string, 
 			         published 		: any) : void
{
   this._LOCAL.schedule({
      id     : 1,
      title  : 'Heads Up!',
      text 	 : notification,
      at  	 : published,
      data   : { message : message }
   });


   // If the local notification has been successfully scheduled
   // then inform the user
   if(this._LOCAL.isScheduled(1))
   {         
      this.notificationExists = true;
      this.displayAlert('Congratulations', 'Your notification has been successfully scheduled');
   }
   else
   {
      this.displayAlert('Oh-oh!', 'Notification failed. There be gremlins at work here.');
   }
}

Cancelling a scheduled notification is handled with the cancelNotification method which uses the supplied id of the notification that we want to cancel:

/**
 * Cancel a scheduled Local Notification and inform the user of success/failure
 *
 * @public
 * @method cancelNotification
 * @param id  		{Number} 	The id of the local notification to be cancelled
 * @return {None}
 */
cancelNotification(id : number) : void
{
   this._LOCAL
   .cancel(id)
   .then((data) =>
   {
      this.notificationExists = false;
      this.displayAlert('Success', 'All notifications have been cancelled');
   })
   .catch((error) =>
   {
      this.displayAlert('Error', error);
   });
}

The DatePicker plugin functionality is introduced and managed using the selectDateForScheduling method.

This will be used to assign the desired date/time for the local notification to be published:

/**
 * Select a date/time
 *
 * @public
 * @method selectDateForScheduling
 * @return {None}
 */
selectDateForScheduling() : void
{
   this._DATE.show(
   {
      titleText            : 'Select a date/time for this notification to be published',
      todayText            : 'Select date',
      nowText              : 'Select time',
      date 			       : new Date(),
      mode 			       : 'datetime',
      androidTheme 	       : this._DATE.ANDROID_THEMES.THEME_DEVICE_DEFAULT_LIGHT,
      allowOldDates        : false,
      allowFutureDates     : true
   })
   .then((date : any) => 
   {
      this.published 	 = date;
   })
   .catch((err) => 
   {
      this.displayAlert('Error', err);
   });
}

The generateReminder method is called upon form submission and takes the completed form data/date selection, supplying these to the scheduleNotification method to generate the local notification that will be published at the assigned date and time:

/**
 * Generates a Local Notification for a scheduled date/time
 *
 * @public
 * @method generateReminder
 * @return {None}
 */
generateReminder() : void
{
   let notification  : string 		=	this.form.controls['notification'].value,
       summary       : string 		=	this.form.controls['summary'].value,
       published     : string 		=	this.published;

   this.scheduleNotification(notification, summary, published);
   this.clearForm();
}

Regardless of whether a local notification could be generated, a date/time selected or the outcome of other operations was successful or not the user will be kept informed courtesy of the displayAlert method:

/**
 * Display an alert box
 *
 * @public
 * @method displayAlert
 * @param title 		  	{String} 		The heading for the alert
 * @param message  			{String} 		The message to be displayed
 * @return {None}
 */
displayAlert(title 		: string, 
   			 message 	: string) : void
{
   let alert : any 		=	this._ALERT.create({
       title 		: title,
       subTitle  	: message,
       buttons      : ['Got it']
   });
   alert.present();
}

Finally, we add the clearForm method which does exactly what it says:

/**
 * Clear the form fields of data
 *
 * @public
 * @method clearForm
 * @return {None}
 */
clearForm() : void
{
   this.notification 	= '';
   this.summary 		= '';
   this.published   	= '';
}

The HomePage component logic in full

With the logic for our ionic-notify/src/pages/home/home.ts component class now completed we should see the following code contained within this file:

import { Component } from '@angular/core';
import { AlertController, NavController, Platform } from 'ionic-angular';
import { FormBuilder, FormGroup, Validators } from '@angular/forms'; 
import { DatePicker } from '@ionic-native/date-picker';
import { LocalNotifications } from '@ionic-native/local-notifications';

@Component({
  selector: 'page-home',
  templateUrl: 'home.html'
})
export class HomePage {




   /**
    * @name form 
    * @type {FormGroup} 
    * @public
    * @description              References a FormGroup object for use
                                with form validation/management
    */
   public form                  : FormGroup;




   /**
    * @name notification 
    * @type {String} 
    * @public
    * @description              Stores the title for the local notification 
    */
   public notification : string;




   /**
    * @name summary 
    * @type {String} 
    * @public
    * @description              Stores the message supplied by the local notification 
    */
   public summary : string;




   /**
    * @name published 
    * @type {String} 
    * @public
    * @description              Stores the published date supplied for the local notification 
    */
   public published : any;




   /**
    * @name notificationExists 
    * @type {Boolean} 
    * @public
    * @description              Determines whether a notification has been scheduled or not 
    */
   public notificationExists : boolean   = false;




   // Initialise component/plugin modules
   constructor(public navCtrl 	: NavController,
   			   private _ALERT   : AlertController,
   			   private _FB      : FormBuilder,
   			   private _DATE 	: DatePicker,
   			   private _LOCAL   : LocalNotifications,
   			   private _PLAT    : Platform) 
   {
      // Set up form validation - VERY basic
      this.form 		= 	this._FB.group({
         'notification'   : ['', Validators.required],
         'summary'   	  : ['', Validators.required],
         'published'      : ['', Validators.required]
      });
   }




   /**
    * Register click event for Local Notifications on view load 
    *
    * @public
    * @method ionViewDidLoad
    * @return {None}
    */
   ionViewDidLoad() : void
   {
      // Trigger notification event listener ONLY when the
      // platform is detected/fully initialised
      this._PLAT
      .ready()
      .then(() =>
      {
      	 
         // Register click event listener for each local notification
         this._LOCAL.on('click', (notification, state) =>
         {
            var title 	 		=	notification.title,
            	message  		= 	JSON.parse(notification.data);

            // Display the supplied message to the user
            this.displayAlert(title, message.message);


            // Now hide the Cancel notification button from view
            if(this.notificationExists)
            {
               this.notificationExists = false;
            }

         });

      });
   }




   /**
    * Schedule a Local Notification and inform the user of success/failure
    *
    * @public
    * @method scheduleNotification
    * @param notification  		{String} 		The text for the local notification
    * @param message  			{String} 		The message to be displayed once the local notification has been clicked on
    * @param published  		{String} 		The date/time when the local notification will be published
    * @return {None}
    */
   scheduleNotification(notification 	: string, 
   						message 		: string, 
   						published 		: any) : void
   {
      this._LOCAL.schedule({
         id     : 1,
         title  : 'Heads Up!',
         text 	: notification,
         at  	: published,
         data   : { message : message }
      });


      // If the local notification has been successfully scheduled
      // then inform the user
      if(this._LOCAL.isScheduled(1))
      {         
         this.notificationExists = true;
         this.displayAlert('Congratulations', 'Your notification has been successfully scheduled');
      }
      else
      {
         this.displayAlert('Oh-oh!', 'Notification failed. There be gremlins at work here.');
      }
   }




   /**
    * Cancel a scheduled Local Notification and inform the user of success/failure
    *
    * @public
    * @method cancelNotification
    * @param id  		{Number} 		The id of the local notification to be cancelled
    * @return {None}
    */
   cancelNotification(id : number) : void
   {
      this._LOCAL
      .cancel(id)
      .then((data) =>
      {
         this.notificationExists = false;
         this.displayAlert('Success', 'All notifications have been cancelled');
      })
      .catch((error) =>
      {
         this.displayAlert('Error', error);
      });
   }




   /**
    * Select a date/time
    *
    * @public
    * @method selectDateForScheduling
    * @return {None}
    */
   selectDateForScheduling() : void
   {
      this._DATE.show(
      {
         titleText            : 'Select a date/time for this notification to be published',
         todayText            : 'Select date',
         nowText              : 'Select time',
         date 			      : new Date(),
         mode 			      : 'datetime',
         androidTheme 	      : this._DATE.ANDROID_THEMES.THEME_DEVICE_DEFAULT_LIGHT,
         allowOldDates        : false,
         allowFutureDates     : true
      })
      .then((date : any) => 
      {
         this.published 	 = date;
      })
      .catch((err) => 
      {
         this.displayAlert('Error', err);
      });
   }




   /**
    * Generates a Local Notification for a scheduled date/time
    *
    * @public
    * @method generateReminder
    * @return {None}
    */
   generateReminder() : void
   {
      let notification  : string 		=	this.form.controls['notification'].value,
          summary       : string 		=	this.form.controls['summary'].value,
          published     : string 		=	this.published;

      this.scheduleNotification(notification, summary, published);
      this.clearForm();
   }




   /**
    * Display an alert box
    *
    * @public
    * @method displayAlert
    * @param title 		  		{String} 		The heading for the alert
    * @param message  			{String} 		The message to be displayed
    * @return {None}
    */
   displayAlert(title 		: string, 
   				message 	: string) : void
   {
      let alert : any 		=	this._ALERT.create({
         title 		: title,
         subTitle  	: message,
         buttons    : ['Got it']
      });
      alert.present();
   }




   /**
    * Clear the form fields of data
    *
    * @public
    * @method clearForm
    * @return {None}
    */
   clearForm() : void
   {
      this.notification 	= '';
      this.summary 			= '';
      this.published   		= '';
   }

}

Templating the application

All that remains now is to add the necessary templating to the application so we can actually generate and manage local notifications.

To do this open the ionic-notify/src/pages/home/home.html template and modify the existing code so that it resembles the following:

<ion-header>
   <ion-navbar>
      <ion-title>
         Notify!
      </ion-title>
      <ion-buttons end>
         <button 
            *ngIf="notificationExists"
            ion-button 
            icon-only 
            (click)="cancelNotifications(1)">
            <ion-icon 
               ios="ios-close" 
               md="md-close"></ion-icon> Cancel
         </button>
      </ion-buttons> 
   </ion-navbar>
</ion-header>

<ion-content padding>
   

   <div 
      margin-top 
      margin-bottom>

      <p>Register a local notification using the form below.</p>

      <form 
        [formGroup]="form" 
        (ngSubmit)="generateReminder()"> 
        <ion-list>       


           <ion-item margin-bottom> 
              <ion-input
                 type="text" 
                 placeholder="Message heading" 
                 clearInput=true 
                 [(ngModel)]="notification"
                 formControlName="notification"></ion-input> 
           </ion-item>
  
  
  
           <ion-item margin-bottom> 
              <ion-textarea 
                 placeholder="Message content"  
                 clearInput=true 
                 [(ngModel)]="summary"
                 formControlName="summary"></ion-textarea> 
           </ion-item>
  
  
           <span  
              ion-button 
              block 
              padding 
              color="secondary" 
              (click)="selectDateForScheduling()" 
               margin-bottom>Select publishing date/time</span>          
  
           <input 
              type="hidden" 
              formControlName="published"
              [(ngModel)]="published">
     
     
              <button
                 ion-button
                 color="primary"
                 text-center
               block [disabled]="!form.valid">Create notification</button>
         </ion-list> 
      </form>

   </div>   


</ion-content>

With this final piece of the coding in place we can now build and subsequently test/run the application on our handheld device.

To begin with, IF developing for iOS, double-click the ionic-notify Xcode project - located at ionic-notify/platforms/ios/ionic-notify.xcodeproj - to open this within Xcode and ensure that a Team is selected in the Project Targets > Signing section (highlighted in red):

XCode application signing showing the selected team

Now open your system CLI, navigate to the root of the ionic-notify/ directory and run the following commands (substitute android for ios IF developing for that platform instead) to build the application and, once completed, run on a handheld device connected to your computer:

ionic cordova build ios --prod
ionic cordova run ios

All things being well you should be able to generate local notifications and see those displayed akin to the following screen capture (demonstrating the application running on an iPhone):

Local notifications and alert messages being displayed on an iPhone device

In summary

Adding local notifications to an Ionic mobile application is relatively straightforward and the plugin documentation helps make this process even easier (with even further methods and functionality available for use).

In this tutorial we've managed to develop a pretty simple application that allows a user to create/cancel local notifications at will although there's a lot we didn't touch on such as creating batch notifications, adding media etc.

As always I'll leave these to you to experiment with and explore using in your own projects.

If you've enjoyed what you've read and/or found this helpful please feel free to share your comments, thoughts and suggestions in the comments area below.

I explore further projects for the Ionic framework within my e-book featured below and if you're interested in learning more about further articles and e-books please sign up to my FREE mailing list.

Tags

Categories

Post a comment

All comments are welcome and the rules are simple - be nice and do NOT engage in trolling, spamming, abusiveness or illegal behaviour. If you fail to observe these rules you will be permanently banned from being able to comment.

Top