Post navigation

AngularJS and Rails Tutorial: part 6 the team entity, grid filtering, links between pages

Part 6 of a tutorial that connects AngularJS to a Rails backend. This post focuses on updating our modal form to support the “new” function, adding a delete button to our ngGrid, and adding error handling in case our rails application rejects our updates. We also add filters to our grid and automatically populate the team filter when we navigate from a specific club. The previous post was New and Delete, the next post is Tidyup. You can also find the index of the posts in the tutorial, or hit the tutorials menu at the top and select the Rails 3 tutorial.

There is a newer, rails 4 and newer angularJS, version of this tutorial. It is also more complete and has a nicer UI that doesn’t use modal windows, which is probably a better choice for anyone starting fresh today. The first page in that tutorial is here, and the index here.

If you haven’t followed the earlier tutorials, the code can be found on github: tutorial 5.

At the end of this post you’ll expect to have updated the app to look like this:

Clubs offer a link to related teams:

Teams has filtering based on that link:

New team defaults based on filter:

You’ll recall back in the first post we created a teams entity at the same time as we created the clubs entity. The definition for this entity in rails looked like:

Initially we’d like to create a team entity in angular that is like the club entity, that is it is standalone. We can do this by copying the entire club directory, and renaming everything in it from club to team, both the filenames, and everything inside the files. When running search and replace, make sure to be careful on capitalisation – Club->Team, club->team. Things to watch out for are:

You’ll also need to change the contact_officer field in the html templates to be captain – teams have a captain, clubs have a contact_officer

You’ll need to update the src/less/main.less to include team.less. Strictly speaking we’re using the same styles at the moment, so once we tidy up the app we’ll aim to put all the less into a more sensible structure with a set of application-wide styles, and only styles specific to a particular entity turning up in that entity’s less

You need to change app.js to include your new module – league.team

You need to change index.html to include a block for teams. I deleted the github block, and created a new block after club similar to the one we already included for clubs

The unit test will mostly work once you search and replace club/team, but remember the JSON response on a server query needs to be updated (I got mine by just querying the rails server directly and looking at the response)

Run grunt build and check that you now have a teams section of your app that behaves a lot like the clubs section did.

Next, we’d like to have our application create a link between clubs and teams. The way we’re going to do this initially is to use a drop-down on the teams modal to allow you to select one of the clubs.

First, we need access to a list of clubs within our edit team controller. We’re going to do that by using the ClubRes resource that we already defined in the clubs entity. In our teams.js we make the following changes. First, modify the module definition at the very top of your team.js file to include league.club as a dependency:

Finally, when we enter the edit controller, we want to go and get the list of clubs from the ClubRes:

$scope.team = team;
$scope.clubs = ClubRes.query();

Then we need to do the html template updates. We’re going to follow the advice we found from IEnableMuch, which suggests a tidy way to implement this. In the team_edit.tpl.html add in club as a editable field. We’re using a select box, refer to the Angular documentation for information on settings you can use with a select dropdown.

Run grunt build, and see if you get a select dropdown working properly. You’ll probably get a unit test failure, as we have a new http request that the unit test isn’t expecting, so update the edit controller portion of our unit test to expect this query to happen:

What you will probably find is that you’re getting a dropdown that defaults properly and lets you select values, but doesn’t save any changes. This is because we haven’t set club_id as an accessible field in our rails model, so go to your rails project and edit app/models/team.rb, and change the attributes accessible:

attr_accessible :captain, :date_created, :name, :club_id

Try again, you should find your selected club being saved.

Next, we’d like a way to come from an individual club to see all the teams for the club. There are a lot of ways to put this together, but for now we’re going to put a “show teams” button on the clubs list. This will take us to the teams list view, and show the teams for just that club through using a filter. We want that filter to be pushed all the way down to the server, and processed on the server.

First, we’re going to add the “show teams” button to the clubs controller. Edit src/app/club/clubs.js to add the following code to the gridOptions configuration:

Run grunt build and see if this method drives us to the teams page (albeit it isn’t showing us the clubs for our team yet).

Next, we want to add a filter capability to the teams list. The ngGrid documentation describes a filter function, but that is basically a search box. We want something that is more a set of selections per column – sort of like a query builder. From this page I can see at very bottom a plunker that creates a standalone filter box, and in that filter box we can put column names with values. So, for example, we could put “name:John” and it will filter on the column name for all Johns. We’re going to have a go at using something like that for now – although later we would prefer to shift this to the server side.

First, add a filter box to src/app/team/team.tpl.html, this is a text box that is bound to the “filterOptions.filterText” model variable:

Then, add a binding to the grid filtering using the filterOptions. There are two additions here – we create a filterOptions variable right up front so the control has something to bind to, then we use that in the gridOptions configuration:

Run grunt build to see how we’re going on the teams page. This should now allow filtering on the teams page, for example you can put “captain:John” into the filter box, it should show just captains with name John.

Our next extension is that we haven’t shown the club names or ids in the list, and while we’re at it we’d like to show and format the create date. Start back in the rails app/controllers/teams_controller.rb – we want to pull back the club name when we bring back the list of teams:

Call the rails service directly to verify the json is now showing the club_name in the result (http://localhost:3000/teams.json). We then edit our grid options in teams.js to show these extra columns, and to add some extra features to our grid, namely the ability for a user to decide which columns to display (a dropdown top right of the grid), and the ability to group by one or more columns.

I note that dragging and dropping columns into the grouping isn’t yet working for me, I think this is because of not (yet) setting the app to be html5, but the default columns do work:

We want to allow the club id to be a parameter on the URL, and to then put that parameter into the filter box automatically. We can get at parameters that are passed in to us by using the $stateParams, which is part of the $stateProvider module. This replaces the standard $routeProvider module, and is the magic that allows us to move between the pages of our application. We tell our team controller that we have a dependency on $stateParams:

Run grunt build and try modifying the URL on the teams page to provide a club_id, and see it update the filter: http://localhost:3000/teams?club_id=1, change it to http://localhost:3000/teams?club_id=2 and see the filter change.

Modify the club to pass in the id on the url, finishing this part of the integration:

Run grunt build, and check that using the “show teams” button on the club page takes you to a filtered list of the teams on the team page.

Finally, when a filter is set on the teams page, we want to apply that filter as a default value when we create a new team. To do this, we’re going to set the club_id in the newTeam method on the controller if there is a club_id in the controller.

And that should do it – when we create a new team it should use the current club if we passed one in on the URL.

You should have an application that has a teams UI, and linkages from the clubs to the teams including a dropdown. It should default the filtered teams into a new team created. It should broadly look like: