Coding an Ionic Application powered by node and MongoDB

December 22, 2017, 8:30 am Categories:

Categories

In the previous tutorial we completed the Node/ExpressJS server-side development for the Ionic Gallery application (that is until we add the PDF rendering functionality in the next and final part of this tutorial series).

In this tutorial we're going to concentrate on developing the project's Ionic application (that we created the initial foundations for in the first tutorial of this series) which can be found in the following project directory:

ionic-crud
    |
    | - app
         |
         | - ionic-gallery
                  |
                  | - .editorconfig
                  |
                  | - .git/
                  |
                  | - .gitignore
                  |
                  | - .sourcemaps/
                  |
                  | - config.xml
                  |
                  | - ionic.config.json
                  |
                  | - node_modules/
                  |
                  | - package.json
                  |
                  | - platforms/
                  |
                  | - plugins/
                  |
                  | - resources/
                  |
                  | - src/
                  |
                  | - tsconfig.json
                  |
                  | - tslint.json
                  |
                  | - www/

    |
    | - server

We'll cover the logic, templating and, where required, the styling for the Ionic application by focussing on the following key areas:

  • HomePage component
  • ViewGalleryPage component
  • ManageGalleryItemPage component
  • ImageProvider service
  • The application's app.scss global stylesheet file

As we have only the one service for the application we'll start our development there before progressing onto each of the page components.

Managing device images

Remember the ImageProvider service we created back in the first part of this tutorial?

We'll use this service to manage interacting with the device camera and photolibrary with methods supplied by the installed Ionic Native Camera plugin.

This won't be particularly involved as all we require from this service is the following:

  • Allow access to the device camera to take photographs and return these as a base64 data URI
  • Allow access to the device photolibrary to select images and return these as a base64 data URI

Open the ionic-crud/app/ionic-gallery/src/providers/image/image.ts service and add the following code:

import { HttpClient } from '@angular/common/http';
import { Injectable } from '@angular/core';
import { Camera, CameraOptions } from '@ionic-native/camera';


@Injectable()
export class ImageProvider {



   /**
    * @name cameraImage 
    * @type {String} 
    * @public
    * @description              Stores the returned base64 data URI
    */
   public cameraImage : String



   constructor(public http     : HttpClient,
               private _CAMERA : Camera)
   {

   }



   /**
    * Uses the Ionic Native Camera plugin to open the device camera
    * and allows the user to take a photograph which is then returned 
    * as a base64 data URI
    *
    * @public
    * @method takePhotograph
    * @return {Promise}
    */
   takePhotograph() : Promise<any>
   {
      return new Promise(resolve =>
      {
         this._CAMERA.getPicture(
       {
          destinationType : this._CAMERA.DestinationType.DATA_URL,
          targetWidth     : 320,
          targetHeight    : 240
       })
       .then((data) =>
       {
          this.cameraImage  = "data:image/jpeg;base64," + data;
          resolve(this.cameraImage);
       });
      });
   }



   /**
    * Uses the Ionic Native Camera plugin to open the device photolibrary
    * and allows the user to select an image which is then returned as a 
    * base64 data URI
    *
    * @public
    * @method selectPhotograph
    * @return {Promise}
    */
   selectPhotograph() : Promise<any>
   {
      return new Promise(resolve =>
      {
         let cameraOptions : CameraOptions = {
             sourceType         : this._CAMERA.PictureSourceType.PHOTOLIBRARY,
             destinationType    : this._CAMERA.DestinationType.DATA_URL,
           quality              : 100,
           targetWidth          : 320,
           targetHeight         : 240,
           encodingType         : this._CAMERA.EncodingType.JPEG,
           correctOrientation   : true
         };

         this._CAMERA.getPicture(cameraOptions)
         .then((data) =>
         {
            this.cameraImage  = "data:image/jpeg;base64," + data;
      resolve(this.cameraImage);
         });

      });
   }

}

IMPORTANT - There is one additional tweak that will need to be made for the Ionic Native Camera plugin to work on iOS devices.

This involves adding the necessary cocoa keys to request user access to the device camera/photolibrary when using this plugin.

Without these keys in place the Ionic Native Camera plugin functionality won't function so be sure to complete this step before proceeding.

With the logic for this service completed let's develop, in turn, each of the following page components used in the ionic-gallery application:

  • HomePage
  • ViewGalleryPage
  • ManageGalleryItemPage

Crafting the HomePage component

As the landing page for the Ionic application the HomePage component retrieves existing gallery records from the project's MongoDB database and assigns an Update, Delete and View button to each record when displayed in the page template.

Upon initial launch the application is going to display a blank area where the list will subsequently render as there are no existing documents within the MongoDB database (so you might want to consider adding a conditional message to this area which will only be displayed under this particular circumstance).

Of course this isn't going to be much use to us if we can't actually add new documents to the MongoDB database (and subsequently retrieve and display those in the HomePage component's template) so it's important that an Add document button is implemented here.

These UI elements will be rendered like so (with existing records displayed):

Ionic application displaying records as list with images and buttons

The HomePage component class will act as the "glue" that binds the backend (with the calls to the project's node application and retrieving data from the MongoDB database) to the front-end (I.e. what is displayed to the end user).

Let's implement this "glue" by opening the ionic-crud/app/ionic-gallery/src/pages/home/home.ts component class and adding the following code:

import { Component } from '@angular/core';
import { ModalController, NavController, ToastController } from 'ionic-angular';
import { HttpClient, HttpHeaders } from '@angular/common/http';


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


   /**
    * @name items 
    * @type {Array} 
    * @public
    * @description              Used to store the retrieved documents from the 
                                MongoDB database
    */
   public items : Array<any>;



   /**
    * @name _HOST 
    * @type {String} 
    * @private
    * @description              The network IP Address and port number that the
                                node application is running on
    */
   private _HOST : string 			=	"http://ENTER-YOUR-NETWORK-IP-ADDRESS-HERE:8080/";



   constructor(public navCtrl 		: NavController,
   			   private _MODAL  		: ModalController,
               private _TOAST       : ToastController,
   			   private _HTTP        : HttpClient) 
   {
 
   }



   /**
    * Retrieve the documents from the MongoDB database
    * on the ionViewDidEnter lifecycle event
    *
    * @public
    * @method ionViewDidEnter
    * @return {None}
    */
   ionViewDidEnter() : void
   {
      this.retrieve();
   }



   /**
    * Delete a selected document from the MongoDB database
    *
    * @public
    * @method deleteRecord
    * @param item    {Object}      The JavaScript map of data that 
    *                              represents the retrieved document 
    *                              from MongoDB
    * @return {None}
    */
   deleteRecord(item : any) : void
   {
      // Retrieve the document ID from the supplied parameter and 
      // define the URL which triggers the node route for deleting the document
      let recordID 		: string		= item._id,
          url       	: any      	 	= this._HOST + "api/gallery/" + recordID;

      // Use Angular's Http module's delete method 
      this._HTTP
      .delete(url)
      .subscribe((data : any) =>
      {
         // If the request was successful notify the user
         this.retrieve(); 
         this.displayNotification(data.records.name + ' was successfully deleted');      
      },
      (error : any) =>
      {
         console.dir(error);
      });
   }



   /**
    * Retrieve documents from the MongoDB database
    *
    * @public
    * @method retrieve
    * @return {None}
    */
   retrieve() : void
   {
      this._HTTP
      .get(this._HOST + "api/gallery")
      .subscribe((data : any) =>
      {
         // If the request was successful notify the user
         this.items = data.records;     
      },
      (error : any) =>
      {
         console.dir(error);
      });
   }



   /**
    * Send the record (for the selected document from the MongoDB 
    * database) to the manage-gallery page to be edited in the 
    * template form fields
    *
    * @public
    * @method updateRecord
    * @param item    {Object}      The JavaScript map of data that 
    *                              represents the retrieved document 
    *                              from MongoDB
    * @return {None}
    */
   updateRecord(item : any) : void
   {
      this.navCtrl.push('manage-gallery', { record : item });
   }



   /**
    * Add a new record courtesy of the template form fields on 
    * the manage-gallery page
    *
    * @public
    * @method addRecord
    * @return {None}
    */
   addRecord() : void
   {
      this.navCtrl.push('manage-gallery');
   }




   /**
    * View the selected record in a modal window
    *
    * @public
    * @method viewRecord
    * @param item    {Object}      The JavaScript map of data that 
    *                              represents the retrieved document 
    *                              from MongoDB
    * @return {None}
    */
   viewRecord(item : any): none
   {
      let modal = this._MODAL.create('view-gallery', { record : item });
      modal.present();
   }



   /**
    * Displays a message to the user
    *
    * @public
    * @method displayNotification
    * @param item    {String}      The message to be displayed
    * @return {None}
    */
   displayNotification(message : string) : void
   {
      let toast = this._TOAST.create({
         message 	: message,
         duration 	: 3000
      });
      toast.present();
   }

}

Here we simply define the methods that manage retrieving, viewing, adding, updating and deleting documents from the project's MongoDB database.

We use different HTTP methods of the Angular HttpClient module (get, put, post and delete) to manage the specific types of backend calls that we want to make (I.e. using put when we wish to update an existing document or delete when we wish to remove that document from the database).

The URL for each of these calls is defined in the following way:

  1. The IP address of the network that we are connecting to
  2. The port number that the node server is currently running on
  3. The ExpressJS route that we wish to access (I.e. api/gallery)

As for the HomePage component template this simply consists of the following sections:

  • An Add record button
  • A list of the retrieved MongoDB documents
  • A Delete record button for each listed document
  • An Update record button for each listed document
  • A View record button for each listed document

Open the ionic-crud/app/ionic-gallery/src/pages/home/home.html template and add the following markup:

<ion-header>
  <ion-navbar>
    <ion-title>
      Ionic Gallery
    </ion-title>

    <ion-buttons end>
       <button 
          ion-button 
          block 
          color="primary" 
          (click)="addRecord()">Add</button>
    </ion-buttons>
  </ion-navbar>
</ion-header>

<ion-content padding>
   
   <ion-list>
      <ion-item 
         *ngFor="let item of items">
         <ion-avatar item-start>
           <img src="{{ item.thumbnail }}">
         </ion-avatar>
         <h2>{{ item.name }}</h2>

        <ion-buttons end>
           <button 
              ion-button 
              color="danger" 
              (click)="deleteRecord(item)">Delete</button>


           <button 
              ion-button 
              color="secondary" 
              (click)="updateRecord(item)">Update</button>
   
   
           <button 
              ion-button  
              color="primary" 
              (click)="viewRecord(item)">View</button>
         </ion-buttons>
	  </ion-item>
   </ion-list>


</ion-content>

Adding the ViewGallery component code

The ViewGalleryPage component simply manages the display of a selected record from the HomePage component's list.

This is accomplished by retrieving the individual record's data, supplied as navigation parameters to the ViewGalleryPage component, and assigning these to public properties which are then displayed inside a modal window launched within the component's template like so:

The View Gallery record modal window displaying an image and text for a selected database record

The logic for this is added to the ionic-crud/app/ionic-gallery/src/pages/view-gallery/view-gallery.ts component class as follows:

import { Component } from '@angular/core';
import { IonicPage, 
         NavController, 
         NavParams, 
         ViewController, 
         ToastController } from 'ionic-angular';
import { HttpClient, HttpHeaders } from '@angular/common/http';


@IonicPage({
   name: 'view-gallery'
})
@Component({
  selector: 'page-view-gallery',
  templateUrl: 'view-gallery.html',
})
export class ViewGalleryPage {


   /**
    * @name name 
    * @type {String}
    * @public
    * @description              Record name value
    */
   public name : string;



   /**
    * @name description 
    * @type {String}
    * @public
    * @description              Record description value
    */
   public description : string;



   /**
    * @name thumbnail 
    * @type {String}
    * @public
    * @description              Record thumbnail value
    */
   public thumbnail : string;



   constructor(public navCtrl 		: NavController, 
   			   public navParams 	: NavParams,
   			   private _TOAST 		: ToastController,
   			   private _VIEW        : ViewController,
   			   private _HTTP 		: HttpClient) 
   {
   }




   /**
    * Retrieve the navigation parameters
    * on the ionViewDidLoad lifecycle event
    *
    * @public
    * @method ionViewDidLoad
    * @return {None}
    */
   ionViewDidLoad() 
   {
      this.name 				=	this.navParams.data.record.name;
      this.description			=	this.navParams.data.record.description;
      this.thumbnail			=	this.navParams.data.record.thumbnail;
      
   }




   /**
    * Call the declared route within the node application to 
    * generate a PDF document based on the supplied parameters
    * sent via the Angular HttpClient POST method
    *
    * @public
    * @method generatePDF
    * @return {None}
    */
   generatePDF() : void
   {
      let headers 		: any		 = new HttpHeaders({ 'Content-Type': 'application/json' }),
          options 		: any 		 = { name : this.name, description : this.description, thumbnail : this.thumbnail },
          url       	: any      	 = this._HOST + "api/generate-pdf";


      this._HTTP
      .post(url, options, headers)
      .subscribe((data : any) =>
      {
         // If the request was successful notify the user
         this.displayNotification(name + ' was successfully created');      
      },
      (error : any) =>
      {
         console.dir(error);
      });
   }



   /**
    * Displays a message to the user
    *
    * @public
    * @method displayNotification
    * @param item    {String}      The message to be displayed
    * @return {None}
    */
   displayNotification(message : string) : void
   {
      let toast = this._TOAST.create({
         message 	: message,
         duration 	: 3000
      });
      toast.present();
   }




   /**
    * Closes the modal window where the component view is displayed
    * @public
    * @method closeModal 
    * @return {None}
    */
   closeModal() : void
   { 
      this._VIEW.dismiss(); 
   }

}

Unsurprisingly the markup structure and content for the ionic-crud/app/ionic-gallery/src/pages/view-gallery/view-gallery.html component template is relatively simple:

<ion-header>
   <ion-navbar>
      <ion-title>View</ion-title>
      <ion-buttons end>
         <button 
            ion-button 
            icon-only 
            (click)="closeModal()">
            <ion-icon 
               ios="ios-close" 
               md="md-close"></ion-icon>
         </button>
      </ion-buttons> 
   </ion-navbar>
</ion-header>


<ion-content padding>

   <img src="{{ thumbnail }}">
   <h2>{{ name }}</h2>
   <div class="description" 
      *ngIf="description" 
      [innerHTML]="description"></div>


   <button 
      ion-button 
      block 
      color="primary" 
      (click)="generatePDF()">Publish to PDF</button>

</ion-content>

You'll notice we've added a generatePDF() method and a button to the component template to enable the displayed record to be published as a PDF document.

Currently this functionality doesn't exist but we will be adding this to the node application in Part 4 of this tutorial series.

Managing updating/adding records

The ManageGalleryItemPage component handles adding new records and editing existing records for the MongoDB database.

The application form with which a record is added to the MongoDB database

The use of the NavParams object determines whether parameters have been supplied for editing an existing record.

If certain parameters are detected the values for these are then assigned to models which allows the supplied record to be edited within the component form template like so:

The application form with which an existing record is updated within the MongoDB database

To implement this functionality open the ionic-crud/app/ionic-gallery/src/pages/manage-gallery-item/manage-gallery-item.ts component class and add the following code:

import { Component } from '@angular/core';
import { HttpClient, HttpHeaders } from '@angular/common/http';
import { IonicPage, 
         NavController, 
         NavParams, 
         ToastController } from 'ionic-angular';
import {
   FormBuilder,
   FormGroup, 
   Validators } from '@angular/forms';
import { ImageProvider } from '../../providers/image/image';


@IonicPage({
	name: 'manage-gallery'
})
@Component({
  selector: 'page-manage-gallery-item',
  templateUrl: 'manage-gallery-item.html',
})
export class ManageGalleryItemPage {




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



   /**
    * @name name 
    * @type {Any} 
    * @public
    * @description              Model for managing input values in the template's 
    *                           name field
    */
   public name                  : any;



   /**
    * @name description 
    * @type {Any} 
    * @public
    * @description              Model for managing input values in the template's 
    *                           description field
    */
   public description		     : any;



   /**
    * @name thumbnail 
    * @type {Any} 
    * @public
    * @description              Model for storing selected image value
    */
   public thumbnail		     : any;



   /**
    * @name displayed 
    * @type {Any} 
    * @public
    * @description              Model for storing selected value from the template's 
    *                           displayed field
    */
   public displayed		     : any;



   /**
    * @name _ID 
    * @type {String} 
    * @private
    * @description              Stores the MongoDB document ID for the record 
    *                           being displayed/amended
    */
   private _ID                  : String;



   /**
    * @name image 
    * @type {Any} 
    * @public
    * @description              Model for storing selected image value
    */
   public image              	: any;



   /**
    * @name pageTitle 
    * @type {Any} 
    * @public
    * @description              Manages the value displayed for the component's 
    *                           page title
    */
   public pageTitle           	: string;



   /**
    * @name _HOST 
    * @type {String} 
    * @private
    * @description              The network IP Address and port number that the
                                node application is running on
    */
   private _HOST : string 			=	"http://ENTER-YOUR-NETWORK-IP-ADDRESS-HERE:8080/";



   constructor(public navCtrl 		: NavController, 
   			   public navParams 	: NavParams,
   			   private _FB          : FormBuilder,
   			   private _HTTP        : HttpClient,
   			   private _TOAST       : ToastController,
   			   private _IMAGE       : ImageProvider) 
   { 
      // Define form validation - VERY basic!
      this.form = this._FB.group({
         'name'        	   : ['', Validators.required],
         'description'     : ['', Validators.required],
         'thumbnail'       : ['', Validators.required],
         'displayed'       : ['', Validators.required]
      });  

   } 



   /**
    * Use the ionViewDidLoad lifecycle event to detect whether particular 
    * navigation parameters were set and, if so, retrieve those and assign 
    * to public properties (which can then be displayed/edited in the template
    * form)
    *
    * @public
    * @method ionViewDidLoad
    * @return {None}
    */
   ionViewDidLoad() : void
   {
     if(this.navParams.get("record"))
     {
        this._ID 				=	this.navParams.data.record._id;
        this.name 				=	this.navParams.data.record.name;
        this.description		=	this.navParams.data.record.description;
        this.thumbnail			=	this.navParams.data.record.thumbnail;
        this.image   			=	this.navParams.data.record.thumbnail;
        this.displayed			=	this.navParams.data.record.displayed;
        this.pageTitle 			=	"Update";
     }
     else {
        this.pageTitle 			=	"Create";     
     }
   }



   /**
    *
    * Handles whether an existing record is being updated or a new record
    * is added to the MongoDB database - this is determined by listening 
    * for the presence of navigation parameters and offering the appropriate 
    * logic for each scenario
    *
    * @public
    * @method manageGallery
    * @return {None}
    */
   manageGallery() : void
   {
      // Retrieve form field values, set up the JavaScript map of values to be 
      // passed to node/MongoDB and declare the URL that we need to supply to 
      // the Angular Http calls
      let name      	: any        = this.form.controls['name'].value,
          description   : any        = this.form.controls['description'].value,
          thumbnail   	: any        = this.form.controls['thumbnail'].value,
          displayed     : any        = this.form.controls['displayed'].value,
          headers 		: any		 = new HttpHeaders({ 'Content-Type': 'application/json' }),
          options       : any	     = { name : name, description : description, thumbnail : thumbnail, displayed: displayed },
          url       	: any      	 = this._HOST + "api/gallery";

      // Do we have a record to update?
      if(this.navParams.get("record"))
      {
         // Use the HttpClient put method to update the existing record
         this._HTTP
         .put(url + '/' + this._ID, options, headers)
         .subscribe((data : any) =>
         {
            // If the request was successful clear the form of data 
            // and notify the user
            this.clearForm();
            this.displayNotification(name + ' was successfully updated');       
         },
         (error : any) =>
         {
            console.dir(error);
         });
      }
      else
      {
         // Use the HttpClient post method to create a new record
         this._HTTP
         .post(url, options, headers)
         .subscribe((data : any) =>
         {
            // If the request was successful clear the form of data 
            // and notify the user
            this.clearForm(); 
            this.displayNotification(name + ' was successfully created');      
         },
         (error : any) =>
         {
            console.dir(error);
         });
      }
   }



   /**
    * Set models/properties to empty string values
    *
    * @public
    * @method clearForm
    * @return {None}
    */
   clearForm() : void
   {
      this.name 		= "";
      this.description	= "";
      this.thumbnail 	= "";
      this.image 		= "";
      this.displayed 	= "";
      this._ID 			= "";
   }



   /**
    * Displays a message to the user
    *
    * @public
    * @method displayNotification
    * @param item    {String}      The message to be displayed
    * @return {None}
    */
   displayNotification(message : string) : void
   {
      let toast = this._TOAST.create({
         message 	: message,
         duration 	: 3000
      });
      toast.present();
   }



   /**
    * Use the device camera to capture a photographic image
    * (courtesy of the takePhotograph method of the ImageProvider
    * service) and assign this, as a bade64-encoded string, to 
    * public properties used in the component template
    *
    * @public
    * @method takePhotograph
    * @return {None}
    */
   takePhotograph() : void
   {
      this._IMAGE
      .takePhotograph()
      .then((image)=>
      {
         this.thumbnail   	= image.toString();
         this.image   		= image.toString();
      })
      .catch((err)=>
      {
         console.log(err);
      });
   }



   /**
    * Use the device photolibrary to select a photographic image
    * (courtesy of the takePhotograph method of the ImageProvider
    * service) and assign this, as a bade64-encoded string, to 
    * public properties used in the component template
    *
    * @public
    * @method selectImage
    * @return {None}
    */
   selectImage() : void
   {
      this._IMAGE
      .selectPhotograph()
      .then((image)=>
      {
         this.thumbnail   	= image.toString();
         this.image   		= image.toString();
      })
      .catch((err)=>
      {
         console.log(err);
      });
   }



}

The logic for this component should be fairly straightforward from the above property/method comments so let's now add the following markup to the ionic-crud/app/ionic-gallery/src/pages/manage-gallery-item/manage-gallery-item template HTML:

<ion-header>
   <ion-navbar>
      <ion-title>
         {{ pageTitle }}
      </ion-title>
   </ion-navbar>
</ion-header>

<ion-content padding>
   

   <p>{{ pageTitle }} this gallery record</p>

   <form 
     [formGroup]="form" 
     (ngSubmit)="manageGallery()"> 
     <ion-list>
         <ion-item margin-bottom> 
            <ion-label>Name</ion-label> 
            <ion-input
               type="text" 
               [(ngModel)]="name"
               formControlName="name"></ion-input> 
         </ion-item>
   
   
         <ion-item margin-bottom>
            <ion-label>Description</ion-label> 
            <ion-textarea
               type="text"
               [(ngModel)]="description"
               formControlName="description"></ion-textarea> 
         </ion-item>


        <ion-item-group>
            <ion-item-divider color="light">Image</ion-item-divider>
            <ion-item>
               <a 
                  ion-button 
                  block
                  margin-bottom
                  color="primary"
                  (click)="takePhotograph()">
                     Take a photograph
               </a>
            </ion-item>

            <ion-item>
               <a 
                  ion-button 
                  block
                  margin-bottom
                  color="secondary"
                  (click)="selectImage()">
                     Select an existing image
               </a>
            </ion-item>

            <ion-item>
               <img [src]="image">
               <input 
                  type="hidden" 
                  name="thumbnail" 
                  formControlName="thumbnail" 
                  [(ngModel)]="thumbnail">
            </ion-item>
         </ion-item-group>


         <ion-item margin-bottom> 
            <ion-label>Is Displayed?</ion-label> 
            <ion-select
               [(ngModel)]="displayed"
               formControlName="displayed">
               <ion-option value="true">True</ion-option> 
               <ion-option value="false">False</ion-option>  
            </ion-select> 
         </ion-item>
   
   
         <button
            ion-button
            color="primary"
            text-center
            block [disabled]="!form.valid">Save this record</button>
      </ion-list> 
   </form>


</ion-content>

With this final addition to the ManageGalleryItemPage component's template we've covered all of the required development for the ionic-gallery mobile application.

Well, almost...

Some slight style tweaks

There is one slight niggle with the rendering of the HomePage component's template - the ion-avatar images are far too small and look, well...kind of stupid.

To rectify this let's open the ionic-crud/app/ionic-gallery/src/app/app.scss file and add the following style rules:

ion-avatar {
   min-width: 75px !important;
   min-height: 75px !important;

   img {
      width: 75px  !important;
      height: 75px  !important;
   }
}

This changes the size of the ion-avatar component/images from rendering at the default size of 40px to 75px instead - which makes for a much nicer sized icon.

Building, running, testing

With this final tweak in place we've now concluded the ionic application development for our tutorial so this would be a good time to actually build the application, deploy this to a handheld device and test that it works!

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

Selecting a team in Xcode for an iOS application

Now open your system CLI, navigate to the root of the ionic-crud/app/ionic-gallery/ 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 add new records and see those displayed akin to the following screen capture (demonstrating the application running on an iPad):

Ionic application displaying records as list with images and buttons

In Part 4 of this series we add the PDF rendering functionality to the node application to conclude our project development.

In summary

We've covered a lot of ground with developing and completing the functionality for the Ionic application that forms the second half of our project (the first half being the Node/ExpressJS/MongoDB aspect of the project that we covered in the previous two tutorials).

With the page components, styling and custom image service in place (as well as our configured cocoa keys) we can now, through our Ionic application, interact with the node server-side application and begin retrieving, adding, editing and deleting records as required.

There is one small discrepancy though.

We've added code within the ViewGalleryPage component to publish the displayed record to a PDF file.

The only problem is that functionality doesn't exist within our node application yet.

We'll return to the Node/ExpressJS area of our project in the next and concluding tutorial for this series to add this PDF rendering logic and enable each displayed gallery record to be published to a PDF file.

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