Ionic Framework, Cordova and File API – A Media Player App

Yves Bamani requested a post to build a media player app using Ionic Framework and Cordova. The mediaPlayer app will show a player interface and a couple of buttons. The user can browse through the filesystem and pick a file to play. The initial request was to play both Audio and Video files inline. But I was only able to get the Audio files to play inline where as the Video will be launched in the device default video player.

Here is a quick demo of the app

Screenshot_2015-03-30-10-53-15 Screenshot_2015-03-30-10-53-24 Screenshot_2015-03-30-10-53-54

Yves also requested for the app to be built using ngCordova. But there are a couple of features in $cordovaMedia like getDuration(media)  and  getCurrentPosition(), which are not working yet. And the $cordovaFile does not have a method to recursively get all the folders in a directory, so I am going to use Cordova API as is and build this app.

You can find the completed here.

So, let us get started.

Prerequisites

You need to have the knowledge of the following to get a better understanding of the code below.

Application Design

The application is pretty simple. When the user launches the app, we show a file browser, where the user can browse through his/her device. Then they can select an audio or video file to play.

We will be using a side menu template, where the player is a instance of  $ionicModal. This modal lives in the background. As mentioned earlier, we will be using the Media API from cordova to manage the audio files and a Video player Cordova plugin by Dawson Loudon named VideoPlayer inspired by Simon MacDonald’s VideoPlayer. All this plugin does is create a new Video Intent and launch it.

I am still looking for a consistent solution on how to implement inline videos. If you do know one, please drop a comment.

I have tested this app on an Android and not on iOS.

Develop the App

Create a new folder named mediaPlayerApp. Open a new terminal/prompt here. We will scaffold the side menu template and then clean it up as per our needs. Run,

ionic start mediaPlayerApp sidemenu

Once the scaffolding is completed, you can CD into the mediaPlayerApp folder and run

ionic serve

and you should see the side menu app in your browser.

The first thing we are going to do is update index.html. Open www/index.html in your favorite editor and update it as below

We have referred the audio service JS code that consist of the logic to deal with the Media API and the controllers file which consist of the controller logic.

Next, open www/templates/menu.html. We will update this file with fewer menu items

We have removed all the old menu items and added 2 new. One to show the player, and one to browse the device.

Now, we will clean up and rename the required files inside www/templates folder

  • Rename login.html to player.html
  • Delete playlist.html
  • Delete playlists.html
  • Delete search.html

Open www/templates/player.html and update it as below

This template will be shown when we init the Ionic Modal. This Modal will always be in the background while the app is running.

This template is the base for showing the audio player. Line 18 consists of the logic to show the seek bar. Line 22 shows the play button, when we have paused the video using the button on line 25. We can also stop the media play back completely using the Stop button.

As you can see from the directives on these buttons, they are subjected to visibility based on the state of the audio file.

Next, open www/templates/browse.html and update it as below

This is a very simple template drive by the files[]  from scope. When the user launches the browse page, we will query the file system and show the root files. Once the user clicks on a particular folder, we query the file system API passing in the current folder as the root and fetch its children.

And when a user selects a file, we check if it is of the type audio or video and then play it. Else we will show a message that we cannot play the selected file.

This completes all our templates. We will now work with the Audio Service. Open www/js folder and create a new file named audio.service.js and update it as below.

Things to notice

Line 1 : We have created a new module named starter.services and added the  AudioSvc to that.

Line 8 : Defines the play audio method, which plays the given src using the Cordova’s Media API.

Line 18 : We create a setInterval for every seconds to execute  getCurrentPosition() and trigger the callback. This way we update the seek bar with the total time and time left.

Line 46 : The logic for resume audio

Line 52 : The logic for pause audio

Line 58 : The logic for stop audio

We will be injecting this service as a dependency in our controller, where we will manage the above API based on the user interactions.

Next, we will update www/js/app.js as below

Things to notice

Line 1 : We create a module named starter and inject ionicstarter.controllers and starter.services as dependencies.

Line 4 : Inside the  $ionicPlatform.ready() we config the keyboard and status bar.

Line 12, 20, 26 : We are building an API to work with the  $ionicLoading  API.

Line 32 : We config the router

Finally, the controllers. Open www/js/controller/js and update it as below

Things to notice

Line 13 : When the app launches, the BrowseCtrl is invoked. Here, we initialize the player as a modal from the template.

Line 19, 23 : We have created 2 methods on  $rootScope that can show and hide the player. This will be used across the app. Take a look at line 5.

Line 27 : The File System traversing starts from here. We wait for the device to be ready.

Line 30 : We call  requestFileSystem() on the window and get the contents of the root directory.

Line 35 : We read all the entries present in the root folder and  call  processEntries() to build an Array of files system items.

Line 156 : Here we get all the entries and a reference Array. We iterate through each item and build an object, which consists of essential information while rendering. This same method will be invoked when ever we are reading entries from the file system and building a UI.

Line 38 : We assign the file info array to  $scope.files. This updates the browse.html template to reflect the files in the root.

Line 49 : Will get invoked when any file or folder name is clicked.

Line 51 : If the selected item is a folder, we check if the item is a navigation item. Navigation items are used to move to folder one level up, which we create for the user to navigate. Based on this condition, we call  processFile() with a URL

Line 115 : Here, we resolve the current URL, and then get the children (files/folders) inside that path and then update  $scope.files.

Line 125 : If the folder is not the root folder and it has children, we append a new  .. One level up item to the top of the list, using which the user can navigate to the parent folder. You can see the same in the demo video. This way, we can recursively show the file system to the user.

Line 57 : If the clicked item is a file, we check it is an Audio file or Video file. If it is a Video file, we will invoke the  VideoPlayer.play() passing in the media URL. We install the Video player plugin next.

Line 63 : If it is an audio file, we will work with the  AudioSvc  service and manage the player.

The file looks pretty complicated but the logic is pretty simple.

Install Cordova Plugins

To run the app, we need 3 plugins.

  1. com.ionic.keyboard
  2. org.apache.cordova.file
  3. org.apache.cordova.media
  4. com.dawsonloudon.videoplayer

To install the plugins run

cordova plugin add com.ionic.keyboard

cordova plugin add org.apache.cordova.file

cordova plugin add org.apache.cordova.media

cordova plugin add https://github.com/dawsonloudon/VideoPlayer.git

Run the App

We need to run the app on a device to test it. First, we will add a platform. Run,

ionic platform add android

And then to the run  the app on a device execute

ionic run

And you should be able to check out the below

 

Hope this post gave you an idea on how to work with File System, Audio and Video APIs.


Thanks for reading! Do comment.
@arvindr21

Getting Started with Angular 2.0

Recently Angularjs team has launched a 5 mins quick start tutorial on getting started with Angular 2.0. I have taken the same tutorial (with minor changes) and explained it below. There are a lot of blanks to be filled, but this is my first attempt at Angular 2.0.

You can find the source code for the Hello World app built in this post here.

So, let us get started with NG2.0.

What is Angular 2.0?

AngularJS 2 is a framework for mobile apps.  It is for desktop as well, but mobile is the hard bit that we will get right first.  The AngularJS you know and, hopefully, love will still be there with data-binding, extensible HTML, and a focus on testability.

You can read more about Angular 2.0 and its proposed features from here.

5min Tutorial by Angular Team

Angular team has released a tutorial on how to get started, where they explain how to setup the project and run a simple Hello World example.

We will follow the same here. The tutorial they have provided is quite self explanatory with some “Googling”.

To get started, create a new folder named ng2 and open a new terminal/prompt here.

Make sure you have Git installed, and run

git clone https://github.com/angular/quickstart.git hello2ng2

This will clone the quick start project to hello2ng2 folder.

The project consists of the following libs (as of today)

  • Pre-built ES5 version of Angular 2 alpha-11
  • Pre-built ES5 version of rtts-assert alpha-6
  • The es6-shim, which includes Traceur, ES6 Module Loader, System, Zone, and Traceur options for meta-data annotations.

Do notice the directory structure

At the root of the directory you have a Gulpfile that consist of simple build tasks to download Angular 2.0 and its dependencies using the ng2build.sh.

To try this out, you need to have Nodejs installed. And Gulp should be installed globally. To install Gulp globally, run

npm install -g gulp

And then, We will install the dependencies for this project. Run

npm install

Now to regenerate Angular and its dependencies, run

gulp

And you can see the dependencies being removed and added again. This is incase you have messed up anything while going through the source code of Angular2.

EcmaScript 6

Before we go further, I would recommend having a knowledge of EcmaScript 6. One of the resource that helped me get started was es6features repo. Simple and lucid explanations of ES6 features.

This knowledge is quite essential as Angular 2.0 is written for ES6 and to support ES5. When we build the Hello World Example, I will point you to the required resources.

Build the App

The Angular tutorial suggests to create the project related files at the root of the directory. With so much going on at the root of the directory, I found it easy to maintain the files inside a folder named app. This situation is temporary till Angular 2.0 moves to a stable release.

So, create a new folder named app at the root of the project. Create a file named index.html inside the app folder. And update it as below

Things to notice

Line 5 : We load up the es6-shim.js from the dist folder to work with ES6 in current browsers.

Line 10 : We created a new component named my-app. We will talk about components soon.

Line 13 : ES6 comes with Modules and Module Loaders. This makes on demand importing very easy. If you have used Requirejs or the Commonjs module system while working with Nodejs, this will look very familiar.

Line 14 : We refer Angular 2.0

Line 15 : We refer Runtime assertions library

Line 16 : We load a file named app.es6 that we will be creating next. This file will consist the definition for  <my-app></my-app>.

Line 20 : We kick off the app.

Next, create a new file named app.es6. The es6 extension indicates that you are loading a file with EcmaScript 6 syntax. (This is more for your text editor to show syntax highlighting. You can js extension as well if you feel that too much is changing).

Update app.es6 file as below

I was overwhelmed as well as confused when I first saw the code. Learning Angular 2.0 is a challenge in itself and adding ES6 touch to that makes this a bit tricky.

Let’s see what we have in this file

Line 1 : If you have already gone through the modules feature, you should understand this syntax. All we are doing here is importing the required components from angular2 to be used in the current file.

Line 4 : The “@” is an annotation. Angular 2.0 uses a library called AtScript (@ script). 

AtScript

JavaScript, the de facto language of the browser, has a large, thriving community. However, it is missing some features which would make it much more manageable for large-scale application development. The goal of AtScript is to enhance the language with these missing features without infringing upon its current capabilities.

You can read more about it : AtScript Primer. As far as I have understood (I could be totally wrong here), AtScript simplifies the syntax of ES6 in its own way. Taking an example from the primer

ES6

AtScript

You can read more about ES6 classes for better clarity.

Though Angular team does not force the users to use AtScript, but it definitely looks like an advantage working with it.

Getting back, As per the docs, Angular 2 works with a concept of components. And a component consist of 2 parts

  1. The Annotation Section – This consist of the meta data (component selector, template) for that component
  2. The Component Controller Section – This is a ES6 Class, from which the template would be reading the properties that are interpolated ({{…}}) inside it .

So, (referring to app.es6)

Line 5 : Identify the selector on page that would be the base for our component

Line 8 : The template to be injected. Notice  {{ name }}

Line 14 : Declare the values to be used in the template. In our case it is World!

And finally on line 19, we bootstrap the component. As per my understanding, this is similar to exporting the main object from this file (analogous to module.exports) but instantiating it before exporting.

That is all we need to build a Hello World app using Angular 2.0.

Launch and test the App

You can use any static server to launch the app. If you have python already installed, you can run

Windows *nix
python -m http.server    python -m SimpleHTTPServer

from inside the hello2ng2 folder or you can use a node module named http-server to do the same. You can install the same using the below command

npm install http-server -g

And then you can launch the static server by running

http-server

from inside the hello2ng2 folder. And then navigate to  http://localhost:8080/app/ you should see

Screen Shot 2015-03-23 at 11.37.56

Next Steps

There are quite a lot of things going on with Angular 2.0 and I think it would take another 3 – 4 months to get a fair idea on where Angular 2.0 is headed to.

You can track the progress here and Angular 2.0 milestones here.

You can also checkout the resources page, which has a few but helpful links on Angular 2.0.


Thanks for reading! Do comment.
@arvindr21

 

Getting Started with ngCordova

In this post, we will take a quick dip into ngCordova and Ionic Framework. We will take a look at setting up ngCordova with IonicFramework, add adding a few cordova plugins and testing it out on a device.

This post is not limited to IonicFramework. You can use the same knowledge with Onsen UI or any mobile hybrid application that is powered by Angularjs.

We are not going to build any specific app, but we will add a few plugins to a demo app and see how it works. This would be the list of plugins we would test drive

Screenshot_2015-03-08-18-52-26

You can find the complete code here. You can use this repo to submit the app we create to Phonegap Build Service.

So, let us get started.

Prerequisites

Before we proceed, you need to have a good understanding of Angularjs, IonicFramework or Onsen UI and Phonegap/Cordova.

Since we are going to work with device specific features, you would need an actual device to test your code. This setup will not run in a browser. Some of the features we are working on, may work on an emulator. Make sure you have setup everything on your machine so you can deploy the code to your device. You can refer PhoneGap 3 CLI Setup on Mac & Windows for more information.

Also, we will be using bower to add ngCordova to our project. Make sure you have git installed on your machine and run

npm install -g bower

Setup Project

Assuming that you have already done

npm install -g cordova ionic

We will scaffold a new Ionic app. Create a new folder named ionCordova. Open a new terminal/prompt here and run

ionic start ionCordova sidemenu

Then run

cd ionCordova

And then

ionic serve

This will launch the side menu template in your default browser.

Next, we will be deploying the app to the phone and testing the base project out. For that, we first need to add the respective platform. I have an Android device, so I will be building a project close to Android.

ionic platform add android

Next, we will install the side menu template on our device. Run

ionic run

Once the app is successfully deployed on to your device, you should see

Screenshot_2015-03-08-17-04-54

Debugging Hybrid apps on Android with Chrome

I highly recommend using  chrome://inspect (Remote Debugging on Android with Chrome) while working with Android devices. You can access your app inside the web-view and debug as if you were working with your app in a browser.

Here is a quick snapshot

Screen Shot 2015-03-08 at 17.08.19

ngCordova

ngCordova was built to help make app development faster and more efficient than ever before. It gives you simple AngularJS wrappers for the most popular Cordova and PhoneGap plugins available, where you can take a picture, scan a barcode, upload a file, turn on your flashlight, get your current location, and much more with just a few lines of code.

Pretty simple! As of today, there are around 63 plugins in the ngCordova arsenal. These wrapper make interacting with device specific features pretty easy.

Setup ngCordova

To setup ngCordova, we will be using bower. Run

bower install ngCordova --save

Next, we will add a reference to it in our index.html. Open www/index.html and update it as below

Notice line 21. ngCordova should be after ionic bundle and before cordova.js reference. This is very very important.

Test ngCordova Setup

To  test the setup, we will print the basic device information on the screen. For that, we will be using the org.apache.cordova.device plugin. This is installed by default if you scaffold an Ionic app.

If you want to explicitly add it, run

cordova plugin add org.apache.cordova.device

First we will inject ngCordova as a dependency to our app. Open www/js/app.js and update

angular.module('starter', ['ionic', 'starter.controllers'])

to

angular.module('starter', ['ionic', 'starter.controllers', 'ngCordova'])

And then, we will update our UI to show the device information. Open www/templates/playlists.html and update it as below

Finally, we will update the PlaylistsCtrl you can ignore the names for now, we will clean up later on. Open www/js/controllers.js and update it as below

Things to notice :

We have removed all the code that we are not going to use.

Line 5 : We have injected $ionicPlatform, $scope and $cordovaDevice as dependencies

Line 6 : This is very important. All your ngCordova code SHOULD be written inside  $ionicPlatform.ready(). Else you will see a lot of undefined errors.

Line 7 : This is only a precaution. There are many instance, when the $scope does not update, so we are wrapping our  $cordovaDevice features inside a  $scope.$apply() so that Angular forces a model update.

Line 11 : We get the device object from $cordovaDevice.getDevice() and from that we extract the information needed as shown from lines 13 to 17 and add it to scope.

That is it!

Save all the files and execute

ionic run

And you should see

Screenshot_2015-03-08-17-25-43

Simple and easy!

Refactor Code

Since we would be working with a set of cordova plugins, we will refactor this template.

Step 1 : Open www/templates/menu.html and update it as below

We have removed the old menu items and added a few of the plugins which we are going to test drive here.

Step 2 : Open www/js/app.js  and update it as below

Added routes for each plugin template.

Step 3 : Open www/js/controllers.js  and update it as below

Step 4 : Rename www/templates/playlists.html to device.html

Step 5 : Delete

  • www/templates/browse.html
  • www/templates/login.html
  • www/templates/playlist.html
  • www/templates/search.html

Step 6 : Create

  • www/templates/battery.html
  • www/templates/camera.html
  • www/templates/motion.html
  • www/templates/notification.html
  • www/templates/network.html
  • www/templates/pin.html
  • www/templates/share.html
  • www/templates/sqlite.html
  • www/templates/toast.html
  • www/templates/vibrate.html

And add the following code into all of them

Save all the files and execute

ionic run

The app should be deployed to your device and there should not be any change in the output. Instead, you should see the update menu

Screenshot_2015-03-08-18-52-26

Since we have already implemented the Device API, we will move on to the Battery API

Battery Plugin

Service : $cordovaBatteryStatus

The BatteryStatus plugin provides an API for the current battery status.

Add battery status Plugin

cordova plugin add org.apache.cordova.battery-status

Open www/js/controllers.js and add the below code

As always we wait for the $ionicPlatform.ready(). Then we register  status event on  $cordovaBatteryStatus. When the value changes, the callback will be called, where we set the  batteryLevel and  isPluggedIn values in scope.

But for some reason the above code does not work. The callback never gets called. But If I use the commented code, it works fine. The same code is used in Loved One Notifier.

Next, open www/templates/battery.html and update it as below

The output when you execute  ionic run,

Screenshot_2015-03-08-19-30-00

As mentioned, the battery status is never invoked.

Camera Plugin

Service : $cordovaCamera

This service makes it easy to use the org.apache.cordova.camera plugin to take pictures and video from a device.

Add Camera Plugin

cordova plugin add org.apache.cordova.camera

Open www/js/controllers.js and add the below code

We define a set of options on which the image would be captured. And when the takePicture() is called, we take a picture and once the user accepts, we show a preview on the page.

Next, open www/templates/camera.html and update it as below

The output when you execute  ionic run,

Screenshot_2015-03-08-19-41-07Once the image is captured after clicking Take a Picture button, the same image preview will appear below.

Screenshot_2015-03-08-19-43-06

Device Motion Plugin

Service : $cordovaDeviceMotion

This plugin provides access to the device’s accelerometer. The accelerometer is a motion sensor that detects the change (delta) in movement relative to the current device orientation, in three dimensions along the x, y, and z axis.

Add Device Motion Plugin

cordova plugin add org.apache.cordova.device-motion

Open www/js/controllers.js and add the below code

The logic is pretty straight forward. On line 4, we get the Acceleration at that moment. And on line 21, we keep watching the acceleration params and update the UI accordingly.

Next, open www/templates/motion.html and update it as below

The output when you execute  ionic run,

Screenshot_2015-03-08-19-57-59

Notification Plugin

Service : $cordovaLocalNotification

The essential purpose of local notifications is to enable an application to inform its users that it has something for them — for example, a message or an upcoming appointment — when the application isn’t running in the foreground. They are scheduled by an application and delivered on the same device.

Add Notification Plugin

cordova plugin add de.appplant.cordova.plugin.local-notification

Open www/js/controllers.js and add the below code

A new notification can be triggered using the  $cordovaLocalNotification.add(). And the rest is taken care by cordova!

Next, open www/templates/notification.html and update it as below

The output when you execute  ionic run,

Screenshot_2015-03-08-20-15-49

And when the  notification is fired (observe the notification bar)

Screenshot_2015-03-08-20-15-58

And finally in the notification panel

Screenshot_2015-03-08-20-16-08

Network Plugin

Service : $cordovaNetwork

The essential purpose of local notifications is to enable an application to inform its users that it has something for them — for example, a message or an upcoming appointment — when the application isn’t running in the foreground. They are scheduled by an application and delivered on the same device.

Add Network Plugin

cordova plugin add org.apache.cordova.network-information

Open www/js/controllers.js and add the below code

Next, open www/templates/network.html and update it as below

The output when you execute  ionic run,

Screenshot_2015-03-08-20-31-47

Pin Dialog Plugin

Service : $cordovaPinDialog

PhoneGap numeric password dialog plugin for Android and iOS.

Add Pin Dialog Plugin

cordova plugin add https://github.com/Paldom/PinDialog.git

Open www/js/controllers.js and add the below code

When the page loads, we show a pin dialog. The user enters a Pin to access the app. Here you can grant access or reject access to the screen based on this logic. For this demo, once the user enters a pin, we show it to the user in a dialog and then print it on the screen.

Next, open www/templates/pin.html and update it as below

The output when you execute  ionic run,

Screenshot_2015-03-08-20-48-05

Screenshot_2015-03-08-20-48-23Social Sharing Plugin

Service : $cordovaSocialSharing

Share images, text, messages via Facebook, Twitter, Email, SMS, WhatsApp, etc using this plugin.

Support

Screen Shot 2015-03-08 at 21.18.17

Add Social Share Plugin

cordova plugin add https://github.com/EddyVerbruggen/SocialSharing-PhoneGap-Plugin.git

Open www/js/controllers.js and add the below code

The nativeShare()  invokes the  $cordovaSocialSharing.share() which triggers the native share sheet. When the user selects an app to share the code with, the message, subject and link will be passed on based on the selected app.

Next, open www/templates/share.html and update it as below

The output when you execute  ionic run,

Screenshot_2015-03-08-21-25-46 Screenshot_2015-03-08-21-25-56 Screenshot_2015-03-08-21-26-14

SQLite Plugin

Service : $cordovaSQLite

Native interface to sqlite in a Cordova/PhoneGap plugin for Android/iOS/WP(8), with HTML5 Web SQL API

Add SQLite Plugin

cordova plugin add https://github.com/brodysoft/Cordova-SQLitePlugin.git

Open www/js/controllers.js and add the below code

You can know more on how to work with SQLite here. The above code is a excerpt of the same. It creates a new table and adds some data.

Next, open www/templates/sqlite.html and update it as below

The output when you execute  ionic run,

Screenshot_2015-03-08-21-58-27Toast Plugin

Service : $cordovaToast

This plugin allows you to show a native Toast (a little text popup) on iOS, Android and WP8. It’s great for showing a non intrusive native notification which is guaranteed always in the viewport of the browser.

Add Toast Plugin

cordova plugin add https://github.com/EddyVerbruggen/Toast-PhoneGap-Plugin.git

Open www/js/controllers.js and add the below code

Simple API to show toasts, with duration and position.

Next, open www/templates/toast.html and update it as below

The output when you execute  ionic run,

Screenshot_2015-03-08-22-06-34 Screenshot_2015-03-08-22-06-48Vibrate Plugin

Service : $cordovaVibration

Vibrate the device programatically.

Add Vibrate Plugin

cordova plugin add org.apache.cordova.vibration

Open www/js/controllers.js and add the below code

Using the $cordovaVibration.vibrate()  we show a simple vibration pattern.

Next, open www/templates/vibrate.html and update it as below

The output when you execute  ionic run,

Screenshot_2015-03-08-22-17-28Don’t ask how the above image proves that the device vibrates when clicked on the button. You have to take my word for it!

With this, we have test driven a few ngCordova plugins and seen how they can be used. The ngCordova docs are pretty good. You can rely on them quite well for results.

If you are facing issue, do post a comment, but before that please check this guide. Hope this post gave you a decent idea on how to work with ngCordova.


Thanks for reading! Do comment.
@arvindr21

Emberjs – A hands on Tutorial

This is a hands on tutorial on Emberjs. We will be covering most of the Ember concepts, so that you can start building Ambitious web apps.

The app which we are going to build is an Online Pizza Store. We will be working with various aspects of Ember in bringing this project to life. The final output would look like

Screen Shot 2015-03-06 at 19.49.56 Screen Shot 2015-03-06 at 19.50.07 Screen Shot 2015-03-06 at 19.50.27 Screen Shot 2015-03-06 at 19.50.52

You can find a live demo of the app here. You can find the completed code here.

So, let us get started.

Mind set

Couple of things before you start working with Ember (totally my opinion)

  1. Emberjs is a “Convention over Configuration” Framework – If you are coming from a traditional web development background, have already worked on frameworks like Backbone or Angular, the coding patterns of Ember may feel very different. And a long term Backbone resource would be utterly confused by how Ember works.
  2. Emberjs has a steep learning curve – If you want to play around with Emberjs building a Hello World app, you would fall in love with it soon. But once you start figuring out things Oh! Boy! it gets tough. I will show you why too.

So, before we proceed, I recommend not bringing your knowledge of other frameworks while working with Ember. Be rooted to the fact that you need to do things the Ember way and thinking otherwise may throw you off track.

And yes, Angularjs also has a steep learning curve too. But because of the framework using HTML for templating and Directives for managing most of the out of box features, Angular is some what easier to get to.

Again, all this is my opinion based on how I felt while I was learning Emberjs.

Hello Ember!

Even before we do anything, we will run a Hello World application, see the output and then continue.

To get us quickly started with an Ember app, the Ember team provides a started kit. If you head to starter-kit repo, you can clone/download it from there. (The ember team has removed the starter kit link from the homepage just a day ago). 

Once you are at the starter-kit repo, you can click on the download button on bottom right hand corner of the page to get a copy of the code.

Once downloaded unzip it and you should see

Screen Shot 2015-03-05 at 15.41.35

The file versions are as of today. To launch the application, you can host it on a LAMP, WAMP, XAMPP or a Python server. Else, if you have Nodejs installed (which I highly recommend having on your machine) you can install a node module named live-server. This is a super awesome node module, that will spawn a static server in the folder from where you are launching, pretty much what we need for this tutorial.

To install, open a new terminal/prompt and run

npm install -g live-server

And then from the folder where you have unzipped the starter-kit, run

live-server

This will spawn a new static server in the current folder and should open the app in your default browser. And also live-server comes with live reload by default. So if we make changes to our Ember app, you need not refresh the web page.

If everything went as expected, you should see

Screen Shot 2015-03-05 at 15.53.56Nothing fancy, just a list of colors being displayed.

Setting up the Ember Inspector

Before we start working with actual Ember code, we will setup the Ember Extension/add-on.

Once you installed the Inspector, you can open your developer tools in Chrome and you should see

Screen Shot 2015-03-05 at 18.07.48And in Firefox open Developer tools NOT Firebug! and you should see

Screen Shot 2015-03-05 at 18.09.33

Ember Concepts

There are a couple of concepts you need to know about Ember before you start playing with it.

  1. Emberjs is a MVC+R (Model + View + Controller + Route) Framework – Ember is heavily route driven when compared with other MVC frameworks. The Ember team believes that the web is URL driven and so should the applications that reside inside them. Hence every “view” is driven via a route. By default there is an Application route that bootstraps the initial application.
  2. Ember has a very strict naming convention in place. Using this Naming convention, the Ember resolver resolves all the routers, controllers, components. So it is very important to understand how Ember expects your app to be structured, so that it can apply the logic you have written.

It is fair to assume that Emberjs does most of the heavy lifting for you, but for you to add customisation to the code, you need to customize routes, controllers, components as needed. This statement would make sense when we start doing some hands on.

MVC+R

Quick overview

  • Model  – Stores Data
  • Views – Displays Data
  • Controllers – Pass the Data from the Model to View (Decorate data)
  • Routes – Invokes a state of the application that triggers a Model > Controller > View

Ember Core Components

Now that we have a context setup and we have seen a basic app, we will take a quick dip into various Emberjs components.

The first and foremost thing you need to do to initialize an Ember app is to execute this line

App = Ember.Application.create();

This tells Ember to initialize a new Ember app and assign it to the App variable. This variable is global and acts like a namespace for our application. Anything that we do from now will be nested inside App.

Routes

Now, when you launch the starter-kit app, and open the dev tools, you will see that there are a few options on the left hand side inside the Ember Inspector.

Screen Shot 2015-03-05 at 18.14.29Select /# Routes  as show above and on the right hand side you would see

Screen Shot 2015-03-05 at 18.15.19

As you can see that Emberjs has already created an Index Route, Controller and Template for you. This is as part of the bootstrapping process.

Now, let us go back the starter app. Open js/app.js in your favourite editor. And where it says

Screen Shot 2015-03-05 at 18.28.55

We will add a new route called about (just for illustration purposes). Update app.js as

Notice Line 5. We have added a new route. Save the file, back to the browser. You should see

Screen Shot 2015-03-05 at 18.32.46We just added a new route and Ember has created a default router, controller, template and URL for this route. This is Ember Magic!

Do notice the names of these components. They all start with the Route Name. When you are in doubt as to what would be the name of a controller for a certain route, you can add that route, open the inspector and Bam!

Now if you want to customize the router (which we would), we will be creating a new AboutRoute  object like

Do notice the naming convention.

And generally here we associate a model like the  IndexRoute

Screen Shot 2015-03-05 at 18.58.15

This brings us to our next component Models

Models

As we already know that Models store data for us. In the  IndexRoute, we are returning an Array of colors. This will then be consumed to display in the template. Sounds simple?

Let us go ahead and add 2 more colors to this list.

Save the file and back to the browser, you should see the 2 new colors reflected in the UI.

Screen Shot 2015-03-05 at 19.03.14

Pretty straight forward.

Controllers

Now, let us say that you want to print the list of colors in ascending order. This is where controllers come in. They decorate your data and make them presentation ready.

Do note that, Models can never talk to Views. It is always the controller that does the communication between them.

To accommodate the new requirement of arranging colors in ascending order, we will create a new controller.

As you might have already guessed, the controller should be named  IndexController.

Add the below code to app.js.

There are quite of lot of things happening in the above code.

  • Line 1 : We extend a new Controller of type Array. There are 2 types of controllers in Emberjs. One is the Object Controller, this controller is used to work with one item in a model. The second one is a Array Controller. This is used to work with an Array of models. This is the one we have used above, since we are dealing with a collection.
  • Line 2 : We create a new function named  sortedModel. This function will return an Array of sorted colors. The syntax  this.get('model') gives us the current model and then we perform a sort() on it and return the sorted array.
  • Line 4 : We return the response of  sortedModel as a computed property. In simple terms,

 A computed property transforms an object’s function into a property.

The Array Controller expects the output of the   sortedModel to be an Array, instead we are returning a function. To patch this, we make this function a computed property.

If you save the file and see the output, there won’t be any change. The list will still be in the same order as we have declared. To make this work, we need to update our template.

Open index.html and take a look at a script tag that looks like

Screen Shot 2015-03-05 at 20.41.49This is a handlebar template with ID as index. Remember we saw the Index template in the inspector, this is where it is coming from. We will talk more about templates in a moment.

For now, replace model  on line 3 above with sortedModel. Save the file and back to browser, you should see

Screen Shot 2015-03-05 at 20.45.21The sorted array!

Now, you can clearly see the amount of learning you need to print an array of colors in ascending order. This is what I meant by learning Ember is steep.

Moving on, we have covered routes, models and controllers. Now finally the Views.

Views

Emberjs uses Handlebar for templating. If you open Index.html, you can see a tag like

This tag stores our templates. And these tags are called as Handlebar Templates. If you notice, we have one more Handlebar template file with id Index. This template will be loaded when we are working with the Index route.

Ember takes care of injecting the model, invoking the controller and parsing the template when we move to a route.

Anything you see in curly braces {{...}}  are called as helpers. Some helpers have a closing as well like the each {{#each}}...{{/each}}. These are called as block helpers.

If you look at the below code

This is the default template that Ember loads while bootstrapping. This template does not have an ID. And do notice the  {{outlet}} helper on line 4. This tells Ember where to place the contents of the child route.

So, in our application, we have a default template that has a heading (Welcome to Ember.js) and we have an Index template when we are on the index route. How will Ember know where to place the contents of the index template? This is where  {{outlet}} helper comes into picture. We will work with  {{outlet}} helper more soon.

Add 2 new MVC+R pieces

Now that we are kind of comfortable with Ember structure, we will add 2 new routes to the application.

  1. About – Will display a static text
  2. Testimonials – Will have a form where the user fills in some text about us and we add that data to the page

So, first we will create 1 new route – testimonials. Since we have already added the about route. The router map would be

about route is static. We do not need a controller for that. We will add only a handlebars template, that has some static data.

Open Index.html and add the about template

Save the files and go back to the browser and navigate to http://0.0.0.0:8080/#/about and you should see

Screen Shot 2015-03-06 at 09.42.20

Simple and easy!

Instead of typing the URL in the browser, we will provide 3 links, that will navigate to the 2 newly created routes and the index route. We will be using a handlebar block helper called as link-to to achieve this.

Update the default template to

The link-to helper takes the route (in quotes) as an argument. If you save the file and go back to the browser, you should see

Screen Shot 2015-03-06 at 09.43.59

If you click on the links, you see the URL/Views changing. Also you can notice that when you navigate to Testimonials, Ember does not throw an error. It shows a default template in it’s place.

Now, let us work on the Testimonials template. The idea behind Testimonial template is that we present the user with a form, where they would enter their name and a message & submit. We will save that data in memory till the user refreshes the page.

So, this is how our template is going to look like

Things to notice

Line 1 : New handlebars template with id testimonials

Line 6 : We will work with a couple of handlebar helper called as input helpers. The out put of line 6 is an input tag. Except, we are adding a new attribute called as value. This value attribute binds with our model named userName. So, we can save the data to our model.

Line 9 : Similar to line 6 except this is a text area and the binding property is message

Line 11 : This is a simple button, that is supposed to invoke a function to save the form data. In Ember, you call methods inside the controller or model using the action helper. Here when we click on the button, a method named  saveTestimonial will be invoked.

Line 14 – 23: We will display all the in-memory testimonials below the form.

Line 15 : We have used another handlebar helper named if. This is a conditional helper. It decides when to show the underlying the content. Here we say that, unless there is at least one testimonial, do not render/show this markup.

Line 17 – 21 : We iterate the in-memory  testimonials array and show the username and message. Pretty straight forward.

If you save the index.html and switch to the browser, you should see

Screen Shot 2015-03-06 at 10.16.41

when you navigate to the testimonials route. A simple form.

Now, to make this form functional, we will add a controller to this route. Add the below code to app.js.

Things to notice :

Line 1 : We have used a Object controller here, because we are going to deal with one testimonial at a time

Line 2 – 4 : We declare 3 properties, that act like model for this template

Line 5 : This is the actions object, which stores a list of methods that can invoked from the view on various user actions.

Line 6 : We have the  saveTestimonial() definition here. We do a simple check of the values and then save it to the  testimonials [].

Line 12 : Notice very carefully that we have used  pushObject() instead of  push() for adding a new object into the   testimonials []. If you use  push() the newly added value will not reflect in the view. This is Ember’s data-binding. We will talk more about it as we go along.

Save all the files and head back to the browser and you should see the same form. But this time, when you enter data, it should reflect below like

Screen Shot 2015-03-06 at 10.31.04

Sweet right! You can try a couple of things. Use push()  instead of pushObject()  and see if things work as expected. And also, after the data is added to the testimonials array, clear the form fields.

Also do note that if you have used  push() while saving the data, it is a one-way data binding. Since we have used  pushObject() it is a two-way data binding.

Data Binding

Let us take a moment in understanding what data binding is all about in Ember. Below are a points from the Ember docs.

  • A binding creates a link between two properties such that when one changes, the other one is updated to the new value automatically.
  • Bindings can connect properties on the same object, or across two different objects.
  • Note that bindings don’t update immediately. Ember waits until all of your application code has finished running before synchronizing changes, so you can change a bound property as many times as you’d like without worrying about the overhead of syncing bindings when values are transient.

This is the glue that connects various pieces of your data together when needed. Also it keeps observing them for changes and can act accordingly.

So far, we have covered most of the core topics that one would need to write a decent application. But we want to build an Ambitious app, so we will dig into couple more core concepts.

  • Ember Object
  • Ember Mixins

Ember Object

Ember.Object is the main base class for all Ember objects.

There is an awesome post by Dan Gebhardt named Understanding Ember.Object, which he wrote exactly 3 years ago. I am going to replicate couple of pieces from same tutorial here.

Creating objects

In ember you can create objects using the syntax

When you create a new object in the console and print the  emberObject, you should see

Screen Shot 2015-03-06 at 11.01.59

There are quite a few properties here and you can explore them from the docs.

To start using the Ember Object, you would use the extend(). Dan Gebhardt used the Person class to explain. I will use a Shape class to explain the same concepts.

Here we create a shape object, that has 2 properties. Now, we will create a new Shape named square.

Now, we can check the inheritance like

A preview of the above in console

Screen Shot 2015-03-06 at 11.21.44Mixins

Another way of implementing complex object in Ember is to use a Mixin. Quoting an example from  Understanding Ember.Object

While extending classes in a hierarchical fashion often works well, there is a tendency to end up with classes such as MaleLeftHandedPetOwnersOfPoodles. Trying to munge together a bunch of separate concerns in a single class can get messy. Ember’s answer to this problem isEmber.Mixin.

With this we have covered most of the essential concepts in Emberjs. There is still a Lottttt left to learn in Ember.

Now, We will be building an Online Pizza Store example using all the above concepts and Ember Data.

So, let us get started.

Online Pizza Store

Application Design

This is a simple website that presents a list of Pizza that a store sells. A user would select the pizza he want and places an order. The app will accept the order and show the same in order history. At a high level there would be 4 pages

  1. Home Page
  2. List of Pizzaz
  3. Pizza Cart Page
  4. Order History

We will not be adding authentication piece for this example.

First thing we do is list out the routes. We will 4 routes and 1 sub-route.

  1. #/pizzaz – Lists all pizzaz
  2. #/pizza – Shows the selected pizza details
  3. #/cart – Shows the pizzaz added to cart
  4. #/history – Show the order history
    1. #/history/details – Show the order details for a given order

Next, we will chalk out Models. There will be 3 models

  1. Pizza Model
  2. Cart Model
  3. History Model

We will be using Ember data and FixtureAdapter to manage the data.

Setup the Project

You can unzip another copy of starter-kit-master and rename it to online-pizza-store. We will be modifying the same template to achieve the online pizza store app.

As mentioned earlier, we will be using Ember Data for managing the data. So, we will download Ember data. Navigate to Tagged Releases, scroll to the very bottom and you should find Ember Data tagged Builds. Below that you can pick a version – tags/v1.0.0-beta.15/ember-data.prod.js. As of today, this is the latest version. You can download the same from here. Save the file to js/libs folder.

Next, for some look and feel, we will add Bootstrap CSS. Head over to getbootstrap.com and either copy the bootstrap.css reference or download a copy of it to your /css folder. Do the same for bootstrap.min.js too.

Next, we will refer the 3 files in index.html. The updated index.html would be

Setup Routes

Next, we will setup the router and routes. The starter template has all the Ember components in one file. This gets kind of messy when we start building an app like the Online Pizza Store. So, we will split the app.js file into multiple files, based on Ember component type.

Create the following files inside the js folder

  • adapter.js – To work with Adapters
  • app.js – App init code
  • components.js – To work with custom components
  • controllers.js – To work with controllers
  • fixture.js – Holds sample data for the app
  • models.js – To work with models
  • router.js – To work with router
  • routes.js – To work with routes

Open app.js and update it as below

Now, we will add a router. Open router.js and update it as

Things to notice

Line 3 : We add the pizzaz route

Line 5 : We add the pizza route that takes in the pizza id as a param

Line 9 : We add the cart route

Line 11 : We add the history route.

Line 12 : Once the history route is registered, we will add a sub-route or a child route which shows the details of the order.

We will look at difference between pizza route and details route when we work with them.

Setup FixtureAdapter

We are going to add a new Application Adapter. Adapters are the way Ember models communicate with the data. Since this is a tutorial app, we will be using memory as our data store. We will enable this using the FixtureAdapter.

Open adapter.js and update it as

Things to notice

Line 1 : We have extended a FixtureAdapter

Line 2 – 8 : We have written a logic to return only a few records from the fixture, if we pass in a start and end value. If you did notice the home page of the app, we have only 4 pizzaz listed at the bottom. We achieve that using the logic written here. The same logic can be used for pagination when using FixtureAdapter.

Setup Fixture data

To work with FixtureAdapter, we need fixture data. So, open fixture.js and update it as

As you can see from above, we are referring to some images. You can get the images from here.

Setup IndexRoute

Next, we will add the definition for IndexRoute. This will load 4 pizzaz from the fixture data. Open routes.js and update it like

If you refer the FixtureAdapter code above, we are passing in the complete array of 8 items and fetching only 4 back here.

Setup Models

Now, we will create the models. Open models.js and update it as

Things to notice

Line 1 :  We extend a pizza model. Do notice that we are using DS (data store)’s version of model here. We have 3 properties. pizza name, pizza image and pizza description. Even though our fixture data is having an ID, we do not add it. Emberjs takes care of it.

Line 7 : We extend a cart model from DS.Model. This model will consist of a list of pizzaz that are present in the current order.

Line 11 :  We extend a history model from DS.Model. This model will consist of all the orders placed so far.

Lin