Thursday, April 25, 2013

Lesson 3: Angular Tutorial and Journey - Forms & CRUD

In Lesson 2 we created a basic structure for our Device Management application. We learned the following:
  1. How to modularize our application using Angular Modules & we created an angular Service which can encapsulate our backend device data. This service can later be extended to retrieve data from the backend services
  2. How to handle different views within the application using Angular Routes. We were able to split our main HTML template into multiple views and assemble at runtime using $routeProvider. We injected the controller and views to the route. 
  3. We setup nginx server to start serving our application behind a webserver
  4. Most importantly, we are also learning how to effectively use github and git

During this part of the journey, lets try to manage our device list. Currently, we have a static list which is stored as an array within a service module. I would like to handle this in a couple of steps... progressively.. [ You can access all the code in this lesson by doing git checkout v1.3.1]

  1. When there are no items in the list, it should display "You have no devices, would you like to add one". This will provide an entry point into adding a device. 
  2. Implement a form which will add a device to our list (although not persisted in a db at this time)
Step 1: Show/Hide a message using ng-show & ng-hide. Angular templating language does not have an if-else conditional keywords. This is mainly due to the fact that angular uses DOM as its templating engine. But ng-show, ng-hide & ng-switch provide a mechanism to do conditional logic. 

In our app, we want to show the message "You have no devices setup. Would you like to add?" at the right time.

Here is simple code addition to do that: (Note:- we will eliminate the need for this later. This is to just show the use of directives ng-hide & ng-show for conditional logic)


Step 2:
This is a bit more involved. If we want to add a form, we have to do a couple of things. First we need to create a HTML partial template, lets call it addDevice.html which will hold our form, then add a .RouteProvider to handle the URL (http://localhost/cotd/#/add), then we need to create a addDevice controller which take the model & insert it into our in memory database.

Here is a simple bootstrap template which just shows the form or angularjs partial. It does nothing at the moment. It uses class control-group, control-label & controls to make sure the forms are all aligned properly. One issue that tripped me was that if I did not have "!DOCTYPE html" in my main.html file, the bootstrap forms text input field width was smaller 18px. Once i added then doctype the sizes looked great.



Now lets add angular model hooks. Angular makes it easy to bind form data into our model. Just by adding ng-model into the input fields, these are now available in $scope within our controllers. This reduces a significant amount of coding, in my opinion. In the gist below, I show the form with the model hooks. Pretty simple way to bind input data so its available in our controller.



Now lets take a look at the controller. The goal here is to take the device and add it to our list. The first neat thing is that "device" javascript object is available to us in the controller with all the data filled in. You can log to the console to see whats in there.

It does not have the id element, so we need to add it, which we will do once I explain how in angularjs the data can being shared between controllers using services.

As we talked about before, Services in Angularjs allows us to encapsulate common functionality within the app, its a singleton so you know there is only one instantiation of it. We can also inject this into multiple controllers.

I did a little refactoring of our original service. First, I moved the data into a data property, then we add a method called query, which just returns the data, and also create an add function, which will push the newly added data into the array object.

The following gist shows the shared service code:



To wrap up, lets look at our controllers. We have 2 controllers, list & add. They are both injected with $scope & "Devices" shared angularjs service. The angularjs service encapsulates the data model.

One last thing we need to do is to figure out how to get back to the DeviceListing page once we are done adding. We can use the angularjs $location.path construct to redirect to the main page.

Update

For updating device information we can reuse the addDevice.html template. The request flow goes like this a) user selects item to edit from the list b) which sends a request in the format #/edit/:id which will be interpreted by the routeProvider & handed over to the editDeviceController which displays the device information c) on edit we update the deviceInfo using our Devices service abstraction. Lets take it one step at a time

Step 1: Reusing addDevice.html template, we will add a new Edit button. We need to hide the add button & show the edit button. Also, when adding a device, we need to show Add & hide Edit. Lets do this using the ng-show & ng-hide directives. Lets bind this using an addFlag variable attached to our scope. This should toggle Add & Edit buttons depending on the controller. 

AddDevice.html
  
 
                       
 


function addDeviceController($scope, $location, Devices)
{
    $scope.add=true;



function editDeviceController($scope, $location, $routeParams, Devices)
{
    $scope.add=false;

Lets add a route for handling edit and inject the editDeviceController & addDevice.html template.



    when('/edit/:id', {
        controller: editDeviceController,
        templateUrl: 'addDevice.html'
    }).





Lets now implement the editDeviceController. We need to do the following, based on the :id parameter, we get the device from the list & inject into $scope so that 2-way binding takes care of displaying the data in the template. Its important that we need to deep copy the device object into Scope, otherwise you will undefined error at runtime. Lets also add an update function which will be triggred when the user clicks on Edit.


Full implementation of the Edit Controller:
function editDeviceController($scope, $location, $routeParams, Devices)
{
    // get the device based on parameter id
    var device = Devices.query()[$routeParams.id];

    // set the add/edit flag
    $scope.add=false;
 
    // deep copies the selected item into scope
    $scope.device = angular.copy(device);

    $scope.update = function(device){
        if(!device) return;
        console.log("in EditCtrl add");

        Devices.update(device);

        // redirect to main screen
        $location.path('#/');
    }
}


Lets take a look at the update functionality within our Service. In this simple case, we just update an array. We will extend the service in later lessons to communicate with a restful backend. But, it solves our purposes.


    items.update = function(device){
        // find the selected device & update
        items.data.forEach(function(item, i){
            if(item.id == device.id){
                // update              
                items.data[i] = device;
                return;
            }
        });
    }




Conclusion


I am truly amazed at all the functionality that angularjs provides. The amount of code required to accomplish this is very low and that is the promise of angularjs.

So, we completed the following within our Angularjs CRUD model:
1. Create - Add Device is fully functional now
2. Read - List Device is fully functional
3 Update - Next Up
4. Delete - Fully functional

Sunday, April 21, 2013

Lesson 2: Angular Tutorial and Journey - Introducing Modules, Services & Routes

We will be building on Lesson-1 during this tutorial. We learned the following:
  1. Using Git, clone the app & get checkout a version using "git checkout v1.0"
  2. We created a very simple app which displays a list of devices
  3. The list of devices is stored in a simple js array for the moment
  4. We are using bootstrap to prettify the display
  5. We created a simple angular 2-way binding between Model ($scope) & the view. We also created a simple controller which fills our model
This lesson we will start with extending the basic app & making it more modular. You can write the full  angular app in one javascript file & a single HTML file. But that will not be good right... So, angular provides some good mechanisms for us to organize our code better. 

Modules & Services

Angular modules provide a mechanism to create services that our app utilizes. Essentially we can group common functionality within modules & then it can be utilized anywhere within the app. We will first create a service module which will move the static list of devices from the controller to a service. 

We will create a simple DeviceModule which will abstract our list of devices. The following Gist shows how to do it following the module definition paradigm that angularjs prescribes.

  • Create new file called deviceService.js
  • Define 'DeviceModule' as an angular module using angular.module('DeviceModule', []);
  • Factory provides a singleton module that we can utilize within our app & provides the list of devices that we can use in our Model. 

Gist -->  Angular DeviceModule

Routes


Routes provide a mechanism which will help organize our project even better and also allows us to create multi-page views.

NOTE:- ROUTES will require setting up an HTTP Server, which will cover at the end. We will setup a nginx server.

STEP 1:
   Simplify our main.html even further by introducing ng-view tag. Move the rest of the functional aspects into separate view html files and controllers.



Step 2:
  Create a listDevices.html which will instantiate the ng-controller & uses ng-repeat to show the devices



Step 3:
   Lets work on the controller to call our deviceModule & populate our model $scope with the list of devices. Lets also create a route which maps a controller to a view.



By the end of this you should have the same app in Lesson-1, but much more structured and modular. The service module abstracts our device Items, we split our html into multiple views which can be managed via routes.

But to make all this work, we need a http server setup that can run our app. The basic steps are listed below.


  1. install ngnix on your machine: brew install nginx
  2. start nginx
  3. If you go to http://localhost:8080 you should see "Welcome to nginx"

Next we need to make sure nginx is pointing to our angular app directory, so it can serve all our assets. But first where is the nginx config file located? Depending on your installation.... In my case it is in /opt/local/etc/nginx/nginx.conf or /usr/local/etc/nginx/nginx.conf

You have to do sudo to edit this config & save it.

Lets tell nginx to listen on port 80 and serve files from our app directory. The below location config entry tells nginx to serve from your app directory, when you enter http://localhost/cotd


      #snip other entries
      server {
        listen       80;
        server_name  localhost;

        location / {
            root   share/nginx/html;
            index  index.html index.htm;
        }
        location /cotd {
            alias /Users/username/angular/cotd/;
            index  main.html;
        }
        #snip other config entries


But, one problem I see is that the styles are all bad. Looks like the bootstrap CSS file is not being served. To fix this lets create an assets directory and copy the bootstrap files into the assets directory.

Now if you do http://localhost/cotd  everything looks good.

You can also get the latest code by doing:

git checkout v1.2

This should show you the assets directory with bootstrap files in it. If you have configured the nginx server as described above you should be able to see the simple device listing with bootstrap styling at http://localhost/cotd









Saturday, April 20, 2013

Lesson 1: Angularjs Tutorial and Learning Journey - Construct a basic Angularjs app

Lesson - 1 Angularjs Tutorial a Learning Journey

Angularjs is a relatively new javascript framework for developing single page architectures. You can read more about it here. I would like to document my learning journey here mainly to make sure I can review it later on & in case it can help some other poor soul. I am taking a deliberate, slow approach and learning on the go. I am no expert so take this as you may, IF you are reading this.

Step 1: Setup our development environment

A single page application requires a number of components to be fully functional. On the client side, we will be using AngularJS, on the server side we will be using Node, the database will be MongoDB. We will also be using a lot of cutting edge javascript frameworks on both client & server for object relational mapper (mongoose), building REST services using express on node, Karma & Mocha for unit testing. 

An essential part of development is to use a source control system. We will use the popular git & github capabilities. This tutorial series is going to help (me mainly) us in slowly building a full application stack and also a robust development framework. We will be going through a lot of git commands, so read up on it here.
My Setup: (pre-req, establish your github account)
  1. Mac OSX 10.8.4
  2. Install mac stand-alone CLT command line tools (mountain lion) 
  3. install homebrew - brew is an excellent package manger for osx, similar to apt-get in linux. Run the following command at your terminal prompt to install brew:
    1. ruby -e "$(curl -fsSL https://raw.github.com/mxcl/homebrew/go)"
  4. brew doctor 
    1. to ensure there are no errors 
  5. brew install git 
    1. git is the source code version control system
    2. git --version -- test to see if git was installed successfully
  6. brew install node
    1.  node --version -- test node and npm (node package manager)
    2.  npm --version
  7. MongoDB
    1. brew update
    2. brew install mongodb
    3. mongod&
    4. mongo
  8. Install nginx
    1. brew install nginx
    2. http://localhost:8080 should verify if the installation was successful
  9. Install sublime text editor
git commands 
  1. mkdir -p $HOME/angular-projects/test-git
  2. cd angular-projects/test-git
  3. touch readme
  4. git init   --- initializes the directory to be git managed
  5. git add readme  --- adds readme created in step 5 to git
  6. git commit -m "whoppa"  
  7. git remote -v (list all remote repositories)
  8. git remote add  -- this will establish a remote repository in github. follow the setup instructions above
  9. git remote rm
  10. // git push [alias] [branch]
    1. git push origin master

Now that you have git[hub] up and running lets do some coding.

Working versions of the code for this project is @ https://github.com/sunkay/cotd.git

Sample Application 

We will be building a simple app that is a practical need I encountered at my work. "A way to list all the devices we have and establish a check-in/check-out process." We have a limited number of devices and need an ability to version control the devices in the queue.

Here is a map of what we want the app to do. This will be a step by step process as we develop an angular based application.
  • Device CRUD (Create, Read, Update, Delete)
    • ListDevices
      • List all device assets
    • Create (addDevice)
      • Name, Asset Tag, category (phone, tablet, laptop), details (android, OSVersion etc ), Owning Group (QA, Dev), Image URL, availability (Default: Yes)
    • Update Device data
    • Delete Device
  • checktoutDevice
    • Name, CorpId, Date, Time, Device
    • Device.available = No
  • checkinDevice
    • device.available = Yes
  • report: list of people with devices
  • report: list of available devices by category

Angular here we come ~:-) 

Lets create a simple angular project for our new app. 

The best way to check this out is to download a git tag:
  1. cd $HOME/angular-projects
  2. git clone https://github.com/sunkay/cotd.git
  3. it should create a directory named cotd
  4. cd cotd
  5. git checkout v1.0
    • checkout using tags (v1.0, v2.0 etc) is being used to version control the lessons. You can go to any lesson and build upon the base using these tags. 

Angular Concepts

Angular projects all begin by defining ng-app. This tells angular which portion of the html should be controlled by angular. In our case the entire app is angular based. Angular implements two-way binding which is very slick and reduces a ton of code that we need to write to make everything work. The two-way binding also makes sure updates are reflected automatically, by re-rendering the DOM when the model changes. Read more about angular here.

main.html: (code is shown below)

  • We create a basic angular app denoted by ng-app. This will start the angular process to treat this as an angular app and start the goodies
  • We define a controller ng-controller='deviceListController" which lists a table of devices with attributes
  • It uses ng-repeat to create a list of devices
  • Fairly straightforward stuff so-far
  • Script Tags are included at the bottom of the main HTML file 

cotd.js: (code is shown below)

  1. This is the controller which creates a simple static data & adds them to $scope so that it is available in the template

Code: main.html & cotd.js
-- --

RUNNING THE APP: 
In your web-browser address bar type: file:///Users/your-username/angular/cotd/main.html#

Very simple steps so far. I am sure I will add more explanations to this as we go along. 

This concludes our initial leg of the journey. We setup our environment, we created a git-hub account,  learned some git commands, created a brand new angular app which works!!! Woo Hoo.....

Tuesday, April 16, 2013

Yeoman Angular Getting Started: A Journey

Getting Started with Yeoman, Angular and eventually Express to create a simple yet fully functional application.

This space is to document my journey in detail, for my own purposes.

Started with reading about Angular.js development, read the recently released book about Angular development and ran through some fairly simple exercises. This led me to figuring out project structure, how to organize an Angular project.

Yeoman, even though its unstable, looks like there is a big following and has some neat features, scaffolding, building, watch etc which might make developing Angular applications simpler & more standardized.

STEP 1: Install Yeoman
pre-req: node & npm should have already been installed

sudo npm install -g yo grunt-cli bower --> Global install

sudo npm install -g generator-angular generator-karma
  1. Karma is used for unit testing
  2. Karma is fully configured when used with angular-generator
cd ang-yo
yo angular
grunt
      returned an error that it requires ruby & compass installed

check if ruby is installed ruby -v

sudo gem update --system
sudo gem install compass

grunt --> build a prod ready version of your app
grunt server --> preview the app w/ live reload
grunt test --> test

cmd: grunt server

This should bring you to the built version launched in the browser

EDIT - I decided to incorporate Yeoman at a later stage since I want to learn the Angular basics first. Without the basics, I was getting very confused with what Yeoman and Yo were doing.

So, the journey definetly should not start with Yeoman.

Back to basics......

Start here by doing a slow paced learning journey using angular (angularjs tutorial):
http://technokayiti.blogspot.com/2013/04/angular-tutorial-learning-journey.html