Let’s pick up where we left off. If you haven’t already, make sure you go through Part 1 to create your base Rails app with the API setup.
You can either continue using the code you have created on part 1 or you can catch up by checking out the tagged code:
$ git clone https://github.com/cavneb/angular_casts $ cd angular_casts $ git checkout step-1 $ bundle install $ rake db:migrate; rake db:migrate RAILS_ENV=test $ rake test $ rake screencast_sync:railscasts
Add Angular Libraries
There are a couple of different ways we can add Angular into our application. Ryan Bates suggests using the angular-rails gem. Even though this is an excellent gem which is well maintained, it’s good to know how to do this without a gem.
In our app we are going to link our scripts using a CDN. We can find the CDN for Angular at https://ajax.googleapis.com/ajax/libs/angularjs/1.0.6/angular.min.js. We will also be adding Angular Resource via the CDN as well.
Update your layout file:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16
Here’s a shortcut to do this:
In this file we create a new module called AngularCasts and assign it to
window.App. We also add the dependency of
ngResource which provides simple REST client functionality.
This is quite a change from what exists in the manifest already. We will add jQuery later, but via CDN. You’ll see why later in this post.
Add the View
Next, we need to create a controller. This will allow us to set up a route to a view.
$ rails g controller home index
This set up the HomeController and added the action index. Before we modify this view, let’s update our layout to acts as an Angular app. This is done by adding the directive
ng-app to our
1 2 3
Now let’s update our index view with some simple Angular code:
1 2 3 4 5 6
Update your routes file to use this view as the root.
1 2 3 4 5 6 7
Note that the line
get 'home#index' was removed. This is not needed because the root path directs to it.
Start up your server and open up http://localhost:3000. Type in your name into the text field. If the content changes as you type, it worked! You now have a functional Angular application!
If you are using Rails 3, you will need to delete the file public/index.html
Now the fun begins!
In order for us to tell the page that it should use the App module, we need to add the module name to the
ng-app directive. Set the value of the attribute to AngularCasts:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19
Now our view knows to use the AngularCasts module.
On lines 9-11 we have added the
<header> content. Make sure you have this in your layout as well.
Create an Angular Controller
1 2 3
On line 1, we create a new Angular controller belonging to App named ScreencastsCtrl. The controller will be referenced in our view as ScreencastsCtrl. For more information on Angular controllers, read http://docs.angularjs.org/guide/dev_guide.mvc.understanding_controller.
Let’s update our view to display the message.
1 2 3
Here we have bound the contents of the div to the controller ScreencastsCtrl. Refresh the browser and you should see ‘Message: Angular Rocks!’.
Make it Pretty!
Lets add the much needed CSS to our application. Copy the following into app/assets/stylesheets/home.css.scss.
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79
Refresh the browser. Ooooh!
Start with the Service
Our Angular controller is going to access the data from our API using ngResource. ngResource enables interation with RESTful server-side data sources.
Angular services are singletons that carry out specific tasks common to web apps. Services are commonly used to perform the XHR interaction with the server. To learn about the differences between services and factories, read this. Let’s start off by creating a service at screencast.js.coffee:
1 2 3
Now tell the controller to use this service:
1 2 3
Update the index view with the following:
1 2 3 4 5 6 7 8 9
Now refresh the page. If all worked well, you should see a list of screencasts on the left side. When we reloaded the page, a GET request was sent to /api/screencasts, populating the screencasts attribute in our scope. This is the power of Angular ngResource.
We are doing great! Now we have a list of screencasts on the side which are clickable. However, we don’t do anything when they are clicked. What we want to do is show the screencast in the main section along with some additional screencast information.
Start off by adding the HTML code which will be used to display the main content. This is done inside the index.html.erb file:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18
On lines 10-17, we have added a div which shows the screencast title and summary. On line 10, we use the ng-show directive which only displays the div if selectedScreencast exists.
Go ahead and refresh the page. You should not see any changes. Click on a screencast. Still no changes.
Click and Show
In order for us to show the main content with the screencast information, we need to do a few things. The first thing we need to do is add an ng-click directive to our screencast list:
1 2 3 4 5 6 7 8 9 10
Now when the list item is clicked the function showScreencast will be triggered with the screencast being passed in to it. Now let’s update our controller with this function:
1 2 3 4 5 6 7 8 9
Refresh your browser and click on a screencast. As my wife would incorrectly say: “Waalah!”
Show the Screencast
After doing a bit of looking around, I found that Flow Player offered the easiest and cleanest way to show videos. Let’s add the dependent scripts and css links to our layout:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22
Create the FlowPlayer Directive
FlowPlayer requires triggering a function flowplayer() to show the video. We could add this into our controller, but we love to learn. Let’s create a directive which listens to the controller and triggers the flowplayer function when showScreencast is called.
1 2 3 4 5 6 7 8 9 10 11 12
Now add the directive into our view:
1 2 3 4 5 6 7 8 9 10 11
Refresh your browser and go nuts!
One final thing that I would like to see is some sort of indicator which lets us know which video is playing on the screencast list. This can be done via CSS and some simple code.
In our CSS file, we have already added some style for an active screencast. Any H3 tag on the side with the class of active will show as red. Try it out by adding the class to our view:
1 2 3 4 5 6 7 8 9 10
Refresh the page. You should now see that every screencast link on the left is red.
For us to make it show for the active screencast only we have to make a few changes to our view and controller. Update the view to use the ng-class directive:
1 2 3 4 5 6 7 8 9 10 11
Note that on line 5 we added the 2nd attribute &index. This is available via the ng-repeat directive and is the index value of the array (integer). We also modified line 6 to use the ng-class directive which only shows “active” if the $index is equal to $scope.selectedRow.
Now update the controller to work with these changes:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15
We have added the new param row to the showScreencast function and set this to $scope.selectedRow. Refresh your browser and see how things have changed.
View the working app at http://angular-casts.herokuapp.com/.
I know there are no front-end tests for this tutorial. This was intentional. They were too hard. I spent hours upon hours trying to get the tests working with $httpBackend and service testing, etc. I tried karma and testem. Too much time. Too little benefit. If you are better at this stuff than I am please send me an email or pull request or something with the changes you’ve made to include the tests. I can always add a Part 3 which is about nothing other than testing the frontend.
Thank you all who have patiently waited for me to finish this post. I learned never to release a post before it has been proofread and run through several times. Next time I’m going to do a screencast.. just like the old days.