AngularJS on Rails
September 16, 2014
Recently, I have started looking into AngularJS, a popular front-end Javascript MVC, to help me write cleaner, better, front-end code. AngularJS, developed by Google, enhances your HTML by providing useful HTML attributes, data-binding, and helpful methods to pull it all together.
To get started on an existing Rails project, you should create a JSON feed, I like to use jbuilder. For example, if your controller looks like:
class PlayerStatsController < ApplicationController
...
def show
team = find_team
@player_stat_column = team.player_stat_columns
@players = team.players
end
...
end
Your jbuilder file would look like:
json.player_stat_column @player_stat_column.names
json.players @players do |player|
json.email player.email
json.stats player.player_stat.statistics
end
This would create a JSON page at whatever the URL is, plus .json
. The JSON page would look then render something that looks like this:
{
player_stat_column: [
"completions",
"attempts",
"goals"
],
players: [
{
email: "me@charliemassry.com",
stats: {
completions: 77,
attempts: 90,
goals: 24
}
},
{
email: "something1@charliemassry.com",
stats: []
}
]
}
Now you have your data, but how do you pass that into the view using AngularJS. Well first, you must require the AngularJS file by typing
<%= javascript_include_tag "https://ajax.googleapis.com/ajax/libs/angularjs/1.2.24/angular.min.js" %>
in either application.html.erb
or typing in
<% content_for :angular do %>
<%= javascript_include_tag "https://ajax.googleapis.com/ajax/libs/angularjs/1.2.24/angular.min.js" %>
<% end %>
in the current file and then adding <%= yield :angular %>
in the application.html.erb
file. In both cases, you must require AngularJS before the standard javascript_include_tag
. One problem with using a “Content Delivery Network” to include the AngularJS library is if you need to work on the project offline, say on a train or such, it won’t work so you will have to manually include the project in your application.
Now that you have AngularJS and you JSON feed set up you can finally begin. First, you need to create the scope of the AngularJS app, so if you are not creating an entire AngularJS app and it will be local to one particular site simply make a div tag that holds the entire partial and pass in the attribute ng-app
and create a module name for it.
<div ng-app="playerStats"></div>
Next, you must require the AngularJS module, so in a Javascript file, let’s call it main.js
and let’s put it in app/assets/javascripts/
. Let’s also make sure to require it before the rest of the Javascript files. So in your application.js
file
...
//= require main
//= require tree .
Now that that’s out of the way we can write our module file, for now it is just a one liner in the main.js
file.
var playerStats = angular.module('playerStats', []);
Now we can move on to our controller.
What I’d like to happen is take our JSON feed and display it on the page and map the players’ stats to the column names. This can be done fairly easily with AngularJS. First you must scope the controller to a particular part of a page. So now your page should look like
<div ng-app="playerStats">
<div ng-controller="playerStatsController"></div>
</div>
Second, create a controller, we’ll put it in app/assets/javascripts/angular/controllers
, and we will call it playerStatsController.js
.
playerStats.controller("playerStatsController", ["$scope", "$http", function($scope, $http){
var path = location.pathname + ".json";
$http.get(path).success(function(data){
$scope.columns = data.player_stat_column;
$scope.players = data.players;
});
}]);
What is happening in this controller is, its name is being assigned and then it is passed in two variables that it has access to, $scope
and $http
. $scope
allows you to pass variables to the view for easy data-binding, and $http
allows you to access other websites. Within the controller, the url plus .json
is being assigned to the path
variable to retrieve data from the JSON feed we created earlier. Once it retrieves the data, it then assigns the Javascript objects to the $scope
so the view will have access to them.
So we will change the view to loop through each of the player
objects and show their stats in the view.
<div ng-app="playerStats">
<div ng-controller="playerStatsController">
<h3>Player Statsheet</h3>
player <span ng-repeat="column in columns">{{column}} </span>
<div ng-repeat="player in players">
{{player.email}} <span ng-repeat="column in columns">{{player.stats[column]}} </span>
</div>
</div>
</div>
First, using the ng-repeat
attribute, it is looping over all the columns. Calling it columns is important, so it knows where to grab the variable from the scope. It will repeat each column and print it out to the document using the {{}}
AngularJS tags. It then loops through each player and calls each column name in the stat and prints out the result using a nested loop. And that’s all there is to getting started with AngularJS on Rails. Stay tuned for a future update on some more advanced functionality.