Angular PhoneCat tutorial using a Grails backend

publish on

An example on how to replace Grails views (gsp) and controllers by Angular Framework

Angular being more and more popular I decided to try using it for one of my new projects. As I'm starting to learn Angular, I followed the excellent tutorial on the Angular website http://docs.angularjs.org/tutorial. In this tutorial there is no particular backend, only JSON files emulating GSON responses from a backend. I decided to create a backend using Grails.

If you only want a Grails template with Angular to play with, you can have the project on Github: https://github.com/BenoitWickramarachi/grails-angular-phonecat

If you are interested to discover how I did to integrate Angular with Grails and loaded the data from JSON file to the database, here are the steps.

Step 1: Data-model

So the first step was to reverse engineered JSON files to find out the data model and then create each Grails domain object:


Phone.groovy:

package com.phonecat

class Phone {

	int age
	String phoneId
	String imageUrl
	String name
	String snippet
	
   static mapping = {
   }
	
    static constraints = {
    }
		
}

You can see codes for all domains object on GitHub https://github.com/BenoitWickramarachi/grails-angular-phonecat/tree/master/grails-app/domain/com/phonecat

I did 3 modifications to the model:

- id for a Phone object was renamed to phoneID because it was a String and I prefered to keep DB generated ids.
- id for a PhoneDetail was also renamed to phoneId for the same reason.
- One of the fields in the Camera object is named Primary which is a reserve keyword, so I renamed it to primaryCamera.

Because of those modifications, I couldn't use default object to JSON converter from Grails.
I had to register 3 customs JSON converters, one for Phone, PhoneDetail and Camera objects.

Phone:

		JSON.registerObjectMarshaller( Phone ) { Phone phone ->
			return [
					age : phone.age,
					id : phone.phoneId,
					imageUrl : phone.imageUrl,
					name : phone.name,
					snippet : phone.snippet
			]
		}

PhoneDetail:

		JSON.registerObjectMarshaller( PhoneDetail ) { PhoneDetail phoneDetail ->
			return [
				additionalFeatures: phoneDetail.additionalFeatures,
				android: phoneDetail.android,
				availability: phoneDetail.availability,
				battery: phoneDetail.battery,
				camera: phoneDetail.camera,
				connectivity: phoneDetail.connectivity,
				description: phoneDetail.description,
				display: phoneDetail.display,
				hardware: phoneDetail.hardware,
				id: phoneDetail.phoneId,
				images: phoneDetail.images,
				name: phoneDetail.name,
				sizeAndWeight: phoneDetail.sizeAndWeight,
				storage: phoneDetail.storage
				]
			}

Camera:

		JSON.registerObjectMarshaller( Camera ) { Camera camera ->
			return [
					primary : camera.primaryCamera,
					features : camera.features,
			]
		}

Now that the data model is defined let's fill the database up using datas provided by JSON files from the tutorial.

To do so I copied each required artefacts from 'app' folder to web-app so that Grails can have access to all Javascripts, CSS, images,... files from the tutorial:


I also copied the phones folder (containing all JSON files) to be able to easily access them within Grails.

Now, we need to load each JSON files into the database. To do so, I parsed each file in the bootstrap.groovy and converted the content (String) to a JSON object,
which I then used to construct a Grails domain object using Data binding (because a JSON object is an array, we can just pass it as a param to each domain object constructor).

def jsonPhones = grails.converters.JSON.parse(file.text)

The only manual operation I needed to do was for the 3 exceptions that I had (2 ids renamed to phoneId, and primary renamed to
primaryCamera). For those properties, I set them directly before persisting each object into the Database:

def jsonPhones = grails.converters.JSON.parse(file.text)
jsonPhones.each {
	Phone phone = new Phone(it)
	phone.phoneId = it.id
	phone.save(flush:true, failOnError:true)
}

I used flush:true to be able to see the data in the DB directly (forcing Hibernate to send SQL queries for each save).

You'll find the full Bootstrap file on GitHub https://github.com/BenoitWickramarachi/grails-angular-phonecat/blob/master/grails-app/conf/BootStrap.groovy

Ok, now that we have our precious datas in a DB, we can start building a Controller to interact with it.

Step 2: Controllers

In the angular tutorial there are only 2 actions:

- Listing all phones ex: /phones/phones.json
- A detailed view of a phone ex: /phones/motorola-xoom-with-wi-fi.json

That means 2 URLs mapping to define (we could have define only one but I found that it was cleaner to separate 'listing phones action' and 'showing phone information action').

class UrlMappings {

	static mappings = {
		
		"/phones/phones.json" {
			controller = "phones"
		}
		
		"/phones/${phoneId}.json" {
			controller = "phones"
			action = "showPhone"
		}
		
        "/"(view:"/index")
	}

}

Then writing the controller is as easy as dropping a few lines of code, thanks to Grails magic:

PhonesController.groovy:

package com.phonecat

import grails.converters.JSON

class PhonesController {

	def index() {
		def json = Phone.list() as JSON
		render json
	}
		
    def showPhone() {
		def json = PhoneDetail.findByPhoneId(params.phoneId) as JSON
		render json
    }
	
}

And it's pretty much it, the backend is ready. Of course we could have add CRUD operations and error management but I wanted to keep it as minimal as possible.

Step 3: Replace Grails views with Angular framework

I copied all the required artefacts from the Angular PhoneCat tutorial under Grails /web-app folder in an earlier step. Now I have to add a new Angular module in the Resources plugin to include them later in a GSP:

modules = {
    angular {
		resource url: 'css/app.css'
		resource url: 'css/bootstrap.css'
		resource url: 'css/animations.css'
	  
		resource url:'js/jquery.js'
		resource url:'js/angular.js'
		resource url:'js/angular-animate.js'
		resource url:'js/angular-route.js'
		resource url:'js/angular-resource.js'
		resource url:'js/app/app.js'
		resource url:'js/app/animations.js'
		resource url:'js/app/controllers.js'
		resource url:'js/app/filters.js'
		resource url:'js/app/services.js'
    }
}

As you might have noticed we don't have any Grails Controllers to render views. We only have one GSP for the whole app index.gsp mapped to '/', as Angular will manage the flow:

<!doctype html>
<html lang="en">
<!--[if lt IE 7 ]>  
<!--[if IE 7 ]>     
<!--[if IE 8 ]>     
<!--[if IE 9 ]>     
<!--[if (gt IE 9)|!(IE)]><!--> <html lang="en" class="no-js"><!--<![endif]-->
	<head>
		<meta http-equiv="Content-Type" content="text/html; charset=UTF-8">
		<meta http-equiv="X-UA-Compatible" content="IE=edge,chrome=1">
		<title>Google Phone Gallery</title>	 
		<meta name="viewport" content="width=device-width, initial-scale=1.0">
		<r:require module="angular"/>
		<r:layoutResources />
	</head>
	
	<body>
	  <div class="view-container" ng-app="phonecatApp">
	    <div ng-view class="view-frame"></div>
	  </div>
	  <r:layoutResources />
	</body>
	
</html>

Conclusion

It was really easy to replace Grails Controllers and views by Angular Framework. Grails converter made it easy to provide JSON data to Angular and
CRUD operations can also be added without pain using Grails REST API. I decided to stick with Angular and see how it goes in a real life project.

I've put the complete project on my Github account. Feel free to fork and improve it:

https://github.com/BenoitWickramarachi/grails-angular-phonecat/tree/master/grails-app/domain/com/phonecat

comments powered by Disqus