Grails Application with AngularJS: Calling a Rest Service – Part 5

Remember the core principle of MVC? Clean separation of model, control and view? Many MVC frameworks, but there hardly is a single framework that provides a puritanical separation between layers. In some, the view is polluted with server-side syntax (jsp, gsp, asp), its equivalents (taglib) or specialized templates (velocity, freemarker); in some others, the server-side code is interspersed with view layer abstractions (css class, href links) or its equivalent html wrappers. One way to measure good separation is how close the view layer is to html semantics itself.

In this part, let us see how we can combine the power of Angular and simplicity of Grails (mainly because of conventions) to make a better separation of model and view.

Note: For the brevity of this post, the tests are not explained, but is included in the github. Specifically, take a look at how angular-mocks provides a cool $httpBackend object that acts as a http service for unit tests and how to invoke them in the controllerSpecs.js.

Goal: Display a star catalog

Techniques Demonstrated

  1. Retrieve Star catalog from server via ajax rest call (demonstrates Rest, Ajax and Angular’s $http)
  2. Show/Hide star catalog (demonstrates Angular’s implicit scope values)
  3. Display the json model in table format (demonstrates Angular’s ng-repeat directive)
  4. Simple Grails 2.3.x Rest services (demonstrates Grails 2.3.x Rest capabilities)

Ingredients

  • Star domain class, decorated with @Resource annotation to make it Rest-enabled
  • New Angular controller to initiate an http request
  • http.get() ajax call to retrieve data from Star domain class and bind to Angular scope
  • Html table to display scope data

Step: Create Star domain class

cmd> cd c:\projects\angrails
cmd> grails create-domain-class angular.Star

Update the code as:

package angrails
import grails.rest.Resource
@Resource(uri='/starCatalog', formats=['json', 'xml'])
class Star {
String name
 String constellation
 //Bayer Designation
 String bd
 //Distance from Earth in light years
 Integer distance
static constraints = {
 }
}

There are many ways to create restful services in Grails 2.3.x, this is one of the easiest ways – create a domain object and add a @Resource annotation. Works for prototypes, demos and really simple applications. For an advanced method, you may want to use RestController and other methods.

Step: Add some seed data to Bootstrap.groovy

def init = { servletContext ->
 new Star(name: 'Aldebaran', constellation: 'Taurus', bd: 'Alpha Tauri', distance: 65).save(flush:true)
 new Star(name: 'Betelgeuse', constellation: 'Orion', bd: 'Alpha Orionis', distance: 640).save(flush:true)
 new Star(name: 'Regulus', constellation: 'Leo', bd: 'Alpha Leonis', distance: 79).save(flush:true)
 new Star(name: 'Spica', constellation: 'Virgo', bd: 'Alpha Virginis', distance: 260).save(flush:true)
 }
cmd> grails run-app
Goto http://localhost:8080/angrails/starCatalog

You should see json representation of the records from Star domain class. Grails auto-generates Rest url end point /starCatalog.

Step: Create Angular Controller and http.get ajax call

Create another controller (next to the MainCtrl) in angrailsApp.js:

angrailsApp.controller('StarCatalogCtrl',
	function ($scope, $http) {

		$scope.getStarCatalog = function () {
			$http.get('/angrails/starCatalog').
				success(function (data) {
					console.log("success: " + data);
					$scope.starCatalog = data;
				}).error(function (data) {
					console.log("error: " + data);
					$scope.starCatalog = data;
				});
		};

		$scope.getStarCatalog();
	}
);

1. As a convention, I keep Angular controller suffix as “*Ctrl”, while Grails controllers as “*Controller”.
2. Observe that one more parameter is being added to the function – $http. When Angular runs the javascript, it injects a http service object into $http automatically.
3. The $http.get() does the ajax call to the auto-generated Grails Rest endpoint
4. The result data is set to a new variable in scope – “starCatalog”. We will use this variable to display the table data

Step: Display data in table

You can run crazy with your imagination on how to display the data, but a simple step is shown here:

<div ng-controller="StarCatalogCtrl">
	<span><a href="#" ng-click="starCatalogShow = !starCatalogShow">Star Catalog</a></span>
	<div ng-show="starCatalogShow">
		<div>
			<table class="table">
				<tr>
					<th>Common name</th>
					<th>Constellation</th>
					<th>Bayer Designation</th>
					<th>Distance from Earth (light years)</th>
				</tr>
				<tr ng-repeat="star in starCatalog">
					<td>{{star.name}}</td>
					<td>{{star.constellation}}</td>
					<td>{{star.bd}}</td>
					<td>{{star.distance}}</td>
				</tr>
			</table>
		</div>
	</div>
</div>

A few points of interest here:

  • AngularJS Directives (ng-show, ng-click, ng-controller, ng-repeat) do appear to be a cleaner way of extending html behaviour.
  • Directive ng-controller=StarCatalogCtrl specifies which controller provides the scope of the data
  • How an implicit scope variable “starCatalog” hides/shows the table (within the span tag, using the ng-show directive)
  • The ng-repeat Angular directive which is the “forEach (item in itemList)” equivalent to iterate through the starCatalog
  • With this approach, the binding between client and server is a clean http call. This gives you the ability to call any rest service, as long as you can process what you get.

And before we go nuts about AngularJS, observe the syntax of the <a> tag. This type of construct was popular pre-jquery times (<a href=”#”, onclick=”javascript:openLink()”>Click me</a>). With jQuery, there was a big drive towards separation of presentation of data and manipulation of data – using $(id).onClick() syntax. But AngularJS has put the old construct right back into vogue now, but with a twist.

Does this bother you? The pendulum of imperative-declarative programming will swing on forever. Meanwhile, take a look at these articles about Remix and Innovation Recycle bin.

Advertisements

3 Responses to Grails Application with AngularJS: Calling a Rest Service – Part 5

  1. Great tutorial here. I am running into one issue that I thought you might shed some light on when you have a chance. When I run-app and go to the index page I am not seeing data injection from angular in the page. Instead I see the angular double curly brackets (for example {{helloText}} or {{star.name}}). I even downloaded your github code and ran it and see the same thing. I am assuming that perhaps the angular library is not being loaded in the page? Thanks for any help!!

    Like

  2. vasya10 says:

    @Dennis

    After checkout, you have to install the angular libs into grails-app/assets/bower_components (see my previous posts for that). The angular libraries are not checked into the github project.

    Check the following things.

    grails-app/assets/bower_components has two subdirs: angular and jquery. This is from where the application.js loads the js libs.
    Modern web browser (if IE – 8 or 9+, later the better)
    Do Chrome F12/Firebug and check if any js is not loading correctly
    Browser console log should say: angrails manifest load complete\ncalling main ctrl
    Browser console log should say: “success …” coming from getStarCatalog

    Like

  3. Awesome! That did it, now I can figure out what I did in my code…probably a typo! Thanks again and really nice blog. I will be checking back here in the future for sure.

    Like

Leave a Reply

Please log in using one of these methods to post your comment:

WordPress.com Logo

You are commenting using your WordPress.com account. Log Out / Change )

Twitter picture

You are commenting using your Twitter account. Log Out / Change )

Facebook photo

You are commenting using your Facebook account. Log Out / Change )

Google+ photo

You are commenting using your Google+ account. Log Out / Change )

Connecting to %s

%d bloggers like this: