Ionic 3 : A Step Forward

Content posted here with the permission of the author, who is currently employed at Josh Software. Original post available here.

Most of the people have already switched from Ionic 1 to Ionic 2. You are maybe one of them and feel more comfortable and settled with Ionic 2. But now the latest version of Ionic i.e Ionic 3 has been released. The change from Ionic 2 to Ionic 3 is nothing as compared to that of Ionic 1 to Ionic 2.

Ionic 3 release is not the framework update. It’s just a major update in Ionic 2. It supports angular 4 and intern follows semantic versioning system of angular( The 3 dots system.).That is MAJOR.MINOR.PATCH. The major update implies that there will be some breaking changes and in case of minor/ patch level update, some API will be changed.

Ionic has come up with many features and improvements over Ionic 2. Basic 3 features I implemented in my app and it helped me a lot. My app is now working much faster. In this blog I am sharing details of these features and steps to implement them:

1. Ionic native plugin support:

The plugin support system has been changed in Ionic native 3.x. These changes are:

  • A native package needs to be installed for every plugin that is added to a project
  • The application root module requires that the native package for each installed plugin is imported and added to the provider’s array

Easy steps to add a new plugin to Ionic 3 project:

1. Install Cordova plugin with the help of ionic CLI command:

ionic cordova plugin add <plugin-name>

2. Install ionic native package for the installed plugin by npm:

npm install --save @ionic-native/<plugin-name>

Note that, we need to just add plugin name after @ionic-native/ path. This command will make entry of same package in package.json.

3. Import installed native package to project.

For that, we need to import it into app.module.ts Open root module of project – /src/app/app.module.ts. Add import statement like, (exmaple: camera plugin)

 import { Camera } from '@ionic-native/camera'; 

Now add entry in providers,

  @NgModule({
  ...
  providers: [
    Camera
  ]
  ...
  })

4. Now wherever you required this plugin, just import it. Fairly simple, right?

Ionic native 3 providing us a Cordova wrapper for more than 130 plugins. Instead of using plugin directly, ionic allows us to import respective plugin wrapper in root module once and use it whenever and wherever we want. This reduces app bundle size and make ionic app run faster

2. Lazy loading:

Loading something as and when required. For example, In a web page if we have 50 images, then for better loading time we would not prefer to load all images at once. As user scroll down, images should load. The Same concept is used in Ionic 3.

Instead of loading everything in a front, it will load the component when needed. This would help in starting ionic app. In big applications, when lots of things need to be loaded in the start, this feature will be helpful.

To implement lazy loading we need to follow some steps. Lets see how we can implement lazy loading in Ionic 3

1. Remove all import statement of a page

Lets take example for HomePage. We need to remove all references of HomePage from all other pages, providers, and modules. Start with src/app/app.module.ts. In this file we will have two arrays: entryComponents and declarations. All the components that we want to load in app, we specify them here. Now we want to load HomePage only when it is requested.

So, first of all remove all the reference of HomePage from app.module.ts includinng import statement.

@NgModule({
  declarations: [
    MyApp,
    HomePage
  ],
  ...
  entryComponents: [
    MyApp,
    HomePage
  ],
  ...
})

2. Create ngModule for HomePage

Create new file src/pages/home/home.module.ts. Add declaraion, import and export statement for HomePage.

import { NgModule } from '@angular/core';
import { IonicPageModule } from 'ionic-angular';
import { HomePage } from './home';

@NgModule({
declarations: [
    HomePage,
],
imports: [
    IonicPageModule.forChild(HomePage),
],
exports: [
    HomePage
]
})
export class HomePageModule {}

3. Add decorator in HomePage

Import IonicPage from ionic-angular and add @IonicPage() decorator to home.ts page.

import { Component } from '@angular/core';
import { NavController } from 'ionic-angular';
import { IonicPage } from 'ionic-angular';

@IonicPage()
@Component({
  selector: 'page-home',
  templateUrl: 'home.html'
})
export class HomePage {
  constructor(public navCtrl: NavController) {}
}

4. Remove all references of HomePage

Remove all the import statements to HomePage from all pages, provides, root files. Now its time to use HomePage module. We can use it by simply specifying HomePage in a string. For example, If you are using it like this:

rootPage:any = HomePage

Now, it should be replaced by,

rootPage:any = 'HomePage'

These are the simple steps to make our app run faster by implementing lazy loading. We just need to create separate ngModule for each component and decorate it with IonicPage.

3. Plugin mocking and browser development:

Till Ionic 2 we were not able to test any plugin in the browser of the ionic app. Ionic 3 provides full support for plugin mocking. This means that we can easily use and test more than 130 plugins in a browser. This makes ionic developer more comfortable to build entire app in browser without any help of device or emulator.

To use this feature we need to create mocks for our plugin to use and make them return proper data.

Native plugin mock is just a copy of actual plugin. It allows user to test the plugin functionality without using actual plugin in browser itself. Lets take exmaple of camera plugin. We will implement getPictures() method and return test data. Lets write camera plugin mock.

1. Create mock folder in root folder

mkdir src/mocks
cd mocks

2. Create camera-mock.ts and overwrite getPictures() method like following:

export class CameraMock {
  getPicture(params) {
    return new Promise((resolve, reject) => {
      resolve("BASE_64_IMAGE_DATA");
    });
  }
}

3. Import camera-mock.ts in app.module.ts and add it to providers array too

import { CameraMock } from "../mocks/camera-mock";
@NgModule({
...
providers: [
...
CameraMock
]
...
})

4. Now plugin mock is ready to use in any component. Just import it and use it.

I recommend you to use Ionic 3 native plugin support as well as load the components as and when required i.e. lazy loading, Surely you will get performance refinement. Also, there is proper documentation available for steps to migrate from Ionic 2 to Ionic 3. You can refer this.

Advertisements
Posted in General | Leave a comment

Record and export Audio files in browser using Recorder.js and upload it on cloud.

Content posted here with the permission of the author, who is currently employed at Josh Software. Original post available here.

In this article, Let’s see how audio recording is possible without any shim or plugin, but only by using the Recorder.js library in the browser and how to upload recorded file on s3 (Or any other cloud storage). Before going to do audio recording first we will see which technology we need and why.

There are resources available for handing these individually but not together. I used references from below links. It is advisable to read below links before proceeding.

Technology Used:

How does the recording process works?

To record audio in the browser, you will need obviously access to the microphone with the getUserMedia API and the AudioContext API, so be sure that your browser supports these APIs

  • Web Audio API

The Web Audio API is a JavaScript API for processing and synthesizing audio in web applications.The API supports loading audio file data in multiple formats, such as WAV, MP3, AAC, OGG and others. Browser’s support for different audio format varies(Check Here).

  • AudioContext API

The AudioContext is used for creating, processing and decoding audio. You need to create an instance of AudioContext class before you can do anything because all are processed / decoded, controlled for audio generation by this API.
How AudioContext declare?:

window.AudioContext = window.AudioContext or window.webkitAudioContext
  • getUserMedia API

Before going to do recording we should know whether our web application can access user’s camera or microphone. So getUserMedia is an API that gives a web page access to a user’s camera and microphone via JavaScript. getUserMedia() has been supported since Chrome 21, Opera 18, and Firefox 17.

Make sure your application is secured with HTTPS protocol to use “getUserMedia API”. It does not work on insecure origins. Starting with Chrome 47, getUserMedia() requests are only allowed from secure origins: HTTPS or localhost.
How to check getUserMedia

if navigator.getUserMedia
  # do something cool
else
  # fallback code
  • Recorderjs

Recorderjs is a JavaScript library that records audio input (Web Audio API AudioNode object) and encodes to audio file image (Blob object). It supports three encoding formats. By using Recorder.js, the recording process is very simple. All that you need to do is to request the microphone in browser, once the user allows the access to the microphone, a stream object is received in the success callback of the initialization.This stream needs to be handled with the createMediaStreamSource method from an instance of the AudioContext API.All the variables should be stored globally or at least accessible in the scope for the rest of functions.

To understand above explanation, added code here:

startUserMedia = (stream) ->
  input = window.audio_context.createMediaStreamSource(stream)
  console.log 'Media stream created.'
  window.recorder = new Recorder(input, 'audio/mp3')
  window.recorder.record()
  console.log 'Recorder initialised.'
  return

The Recorder.js class expects the handled stream as first argument namely the input. With this instance of Recorder.js you can trigger the record method that starts to recording the received Audio and it will run indefinitely until the stop method from the same instance of recorder is triggered.

Export Recorded Audio

Export the Audio Blob from the recorder audio using the exportWAV method of the recorder instance. The exportWAV method can export the audio in wav and mp3 format when the second parameter is specified with the correct mimetype (‘audio/wav’, ‘audio/mp3’). Don’t forget to use the clear method of the recorder to start with a new one later. With the generated blob you will be able to upload it as an audio file to the server, in the same browser or just to play it in the same document.
Added Code here:

createDownloadLink = ->
  recorder and recorder.exportWAV((blob) ->
    url = URL.createObjectURL(blob)
    li = document.createElement('li')
    au = document.createElement('audio')
    hf = document.createElement('a')

    au.controls = true
    au.src = url
    hf.href = url
    hf.download = 'audio.mp3'
    hf.innerHTML = hf.download
    li.appendChild au
    li.appendChild hf
    playRecord.appendChild li

How to record Audio with Recorder.js

To make the explanation as simple as possible, we’ll just write a haml document that implements all the previously described process. It consists of 2 buttons namely Start and Play that triggers the recording process with Recorder.js. When the user stops the recording, it will append an Audio Track to an UL list with a downloadable audio file with like “audio.mp3”:

HAML code:
Create 2 buttons as “Start Recording” and “Stop Recording”

!!!
%html
  %head
    %meta{:content => "text/html; charset=utf-8", "http-equiv" => "Content-Type"}
    %title Live input record and playback
    :css
      ul {
          list-style: none;
      }

      #playRecord audio {
          display: block;
          margin-bottom: 10px;
      }
  %body
    %h1 Recorder.js export example
    %button#start-btn Start recording
    %button#stop-btn{:disabled => "disabled"} Stop recording
    %h2 Stored Recordings
    %ul#playRecord

Click on Start button will start recording and clicking on Stop button will stop recording and export it.

$('#start-btn').on 'click', ->
  if confirm "Once you start recording, you can't pause it."
    initAudioRecording()

$('#stop-btn').on 'click', ->
  stopRecording(this)

stopRecording = (button) ->
  if window.recorder != undefined
    window.recorder  window.recorder.stop()
    createRecording()
    return

createRecording = ->
  recorder and recorder.exportWAV((blob)
    data = new FormData();
    data.append("audio", blob);
    console.log(data)
    $.ajax
      url: 'Your Controller path'
      type: 'POST'
      data: data
      contentType: false
      processData: false
      success: ->
        console.log "Successfully uploaded recording."
  )
  return

startUserMedia = (stream) ->
  input = window.audio_context.createMediaStreamSource(stream)
  # console.log 'Media stream created.'
  window.recorder = new Recorder(input, 'audio/mp3')
  window.recorder.record()
  # console.log 'Recorder initialised.'
  return

initAudioRecording = ->
  try
    window.AudioContext = window.AudioContext or window.webkitAudioContext
    navigator.getUserMedia = navigator.getUserMedia or navigator.webkitGetUserMedia or navigator.mozGetUserMedia
    window.URL = window.URL or window.webkitURL
    window.audio_context = new AudioContext
    console.log 'navigator.getUserMedia ' + (if navigator.getUserMedia then 'available.' else 'not present!')
  catch e
    alert 'No web audio support in this browser!'
  navigator.getUserMedia { audio: true }, startUserMedia, (e) ->
    console.log 'No live audio input: ' + e
    return
  return

Browser Support

  • Make sure you are using a recent version of browser.
  • Make sure your application is secured with HTTPS protocol to use “Web Audio API”. It does not work on insecure origins. As of Chrome 47, the getUserMedia API cannot be called from insecure origins.
  • There is no issue while implementing Web Audio API in development environment i.e. http://localhost:3000
  • You can test your browser compatibility test.Here

How to upload recorded file on s3

Till now we have seen how to get audio blob object, but the major challenge is how to upload this audio blob on s3(or on cloud).
See below coffee script code:

createRecording = ->
  recorder and recorder.exportWAV((blob) ->
    data = new FormData();
    data.append("audio", blob);
    $.ajax
      url: 'Your controller path to upload recording'
      type: 'POST'
      data: data
      contentType: false
      processData: false
      success: ->
        if confirm "Successfully uploaded recording."
          window.location.href = 'Redirect path after successful ajax call.'

To make it very simple to understand I will explain you above code:
I have created a method as “createRecording” which calls exportWAV() method from Recorder.js, so we get a blob object.
Our aim is to upload this blob object on s3, for that I have created FormData() object and append audio blob to FormData() object.
Send this FormData() object to server by ajax call with “POST” method.

NOTE:
As we may be sending large amount of data to server (in terms of MB), we should have proper nginx entry for client_max_body_size.We should change nginx configuration in file /etc/nginx/nginx.conf, to expected max size of our recorded file.

client_max_body_size 50M;

Let’s see server side implementation:

def your_controller_method
    @model_object.audio = params[:audio]
    @model_object.save
    render nothing: true
end

Once file object reaches to your server upload same to S3 (or any other cloud storage) using regular file upload method.

For uploading file we have used carrierwave gem(click here)

Posted in General | Leave a comment

Use power of database to speedup your application!

Learn with fun

In this blog post, I am going to tell you some queries/ tricks to speed up your application by using the power of database. I am using postgres and activerecord rails so all queries are related to these, but you can relate it with your database.

Recently I got some performance issue when our user base increased many folds. We did some optmization and would like to share the tips:

Note: As I am using ActiveRecord most of the examples have ActiveRecord syntax with corresponding SQL statement

Select only required fields from database – Not all

Mostly developers miss to specify the required columns and instead select all fields from database which leads to performance degradation.

Let us say my User Table has 100 users

Above query took 15.4 ms as it is selecting all columns from the table. But, the query below took only 3.3ms.

Here we are not…

View original post 744 more words

Posted in General | Leave a comment

How to upload a large CSV efficiently using rails!

Think, Click and Succeed

Active-record is an abstraction layer that facilitates creation, deletion and use of ORM objects whose data requires persistent storage to a database. This keeps us away from having to think too much about SQL level queries and makes it very easy for us to work with data. It gives us super easy interface that helps us to do “almost” anything that we can do with bare SQL statements. Apart from the basic CRUD operations, active-record lets us do more complicated database stuff like pick a group of records based on a criteria, order them, join tables, perform mathematical operations, etc.

Active-record pattern is liked by most because of the above mentioned reasons. But using active-record solely may not help when your application scales.

For example, active-record does not have a support to bulk insert into the database. Ofcourse we can use gems to do that, but I personally…

View original post 661 more words

Posted in General | Leave a comment

Loading…widgets in react-redux application

I got an interesting requirement for my React app to display multiple widgets with the following conditions:

  1. Number of widgets to displayed – UNKNOWN
  2. Content to be displayed – UNKNOWN
  3. API endpoints – UNKNOWN
  4. Only known thing was the placeholder in the widgets where data needs to be displayed
  5. Need to display loader for each API call

Fortunately, an API was available to get details such as the number of widgets and their endpoints.

As per the requirement to display loader for each API call, the first screen was:

main-widget Initial Loader screen

When the first API returns the response containing details regarding widgets such as the number of widgets and their endpoints, the above widget should turn into the following screen if there are 4 widgets data returned by initial API call:

widget-loaders
screen 2

And each of the widgets will call different APIs to get the data it needs…

View original post 524 more words

Posted in General | Leave a comment

Choosing testing framework for your React application

Let's make learning fun!

Recently, while working on a React/Redux based single page application, I was required to choose a testing framework. Since this was my first attempt at testing JavaScript based front-end applications, I started googling around to find the best possible tool to automate testing of my application. It was not long before I ended up being totally confused. Do you know why?

Because there are too many to choose from and it’s tough to decide, since they all do basically the same thing:

  1. Describe what you’re testing
  2. Set up what you’re going to test
  3. Assert whether the thing did what you expect

Having said that, when you have to choose, no matter how hard it is, you have to choose.

Test tools can be divided based on functionalities that they provide. Some provide us with only one functionality, and some provide us with a combination. It’s common to use a combination of…

View original post 755 more words

Posted in General | Leave a comment

AWS EC2: Increase volume size on the fly

The AWS documentation is pretty detailed and thorough, but sometime I feel it is overwhelming and at times some important steps/command are deep down somewhere, essentially very hard to find or perhaps missing!! I had a similar experience recently.

I hit upon a low disk warning for the root volume of a production instance. I was nervous, but thankfully AWS EC2 supports on the fly increase of volume size (for the kernel that supports on-line resizing, ofcourse). The other option is obviously to create a new instance with larger volume & switch. Not necessary though!!

The first step was to look for documentation and confirm if my instance type supports it. The very first link Google returned was what I was looking for. My Instances are running Ubuntu (mainly 16.04.2 LTS) and AWS does support on the fly volume changes for this. Hurrah!!

The steps in the AWS documentation are certainly detailed but elongated and scattered. It can take a couple of hours to go through and understand the actual set of steps. Additionally, some commands are missing. Let me put down the exact steps and save some trouble 🙂

  1. Increase the volume size: This can be done using “command line” or the “console“. I prefer the console. The steps on the console link are concise.
  2. Monitor the progress: In the AWS documentation go to the section “To monitor progress of a modification from the console”. Once the state is shown as “completed (100%)” proceed to step #3 below. Tip: I increased size from 30GB to 100GB.
  3. Extend the volume’s file system: To take advantage of the increased storage capacity.
    • Check the existing disk configuration by using the command ‘lsblk’. It will show something like below:
      xvda 202:0 0 100G 0 disk
       └─xvda1 202:1 0 30G 0 part /

      This denotes that disk size is 100 GB and allocated to xvda1 is 30GB. Usable is only 30GB, which is on the partition xvda1.

    • Now grow the xvda1 partition to the maximum available disk size. Important: Ensure to use the correct partition. Read ‘growpart’ command documentation, if need be.
      sudo growpart /dev/xvda 1

      you will see a message like below:

      CHANGED: partition=1 start=16065 old: size=62898462 end=62914527 new: size=209699102,end=209715167

      NOTE: The growpart command is missing from the AWS documentation on Extending a Linux File System after Resizing the Volume.

    • Verify that the allocation has changed using the ‘lsblk’ command again. It should now show the entire 100GB allocated to xvda1, as shown below. Tip: At this point the usable space is still ONLY 30GB though it shows 100GB.
      xvda 202:0 0 100G 0 disk
      
      └─xvda1 202:1 0 100G 0 part /
    • Finally tell the OS to use the additional space by resizing the partition.
      sudo resize2fs /dev/xvda1

      you will see a message like below:

      resize2fs 1.42.13 (17-May-2015)
      
      Filesystem at /dev/xvda1 is mounted on /; on-line resizing required
      
      old_desc_blocks = 2, new_desc_blocks = 7
      
      The filesystem on /dev/xvda1 is now 26212387 (4k) blocks long.
    • You will see 100GB allocated to your partition. Verify using ‘df’ command!!
  4. Done. Your volume is now having the increased size!!

IMPORTANT: It is not mandatory, but as a fail safe mechanism, always take an image of the instance that you intend to modify.

NOTE: The option to support on the fly increase in volume size is specific to OS (kernel should support on-line resizing). And, for EC2 the steps could vary as per instance type. However, using the steps above, I have successfully increased the volume size of both m4.xlarge and m4.large instances running ubuntu 16.04.2 LTS.

Posted in General | Leave a comment