AngularJS powered by SilverStripe

Posted by David Craig on 31 March 2014

angularjs and silverstripeMy recent blog post on Backbone unit testing mentioned AngularJS, as being one of the more popular emerging JavaScript frameworks. A common use case for AngularJS is filtering lists of data such as products. I’ve put together an example application which creates a simple product catalogue and more importantly highlights the concept of AngularJS and SilverStripe working together.

On the client-side we have a simple AngularJS application. This manipulates product data and handles user interactions. On the backend, we’ve got a SilverStripe ModelAdmin, Controller, and a custom page type. These are all brought together with AngularJS enhanced SilverStripe templates.

Here’s how it all fits together, starting with the backend.

ModelAdmin

modeladmin

The ModelAdmin is where products are managed. Each product has a title, description, image, and belongs to a product catalogue. The information entered here, is made available to our AngularJS application, via the controller.

Controller

The controller receives AJAX requests from our AngularJS application, and returns JSON containing product information. We take advantage of SilverStripe’s caching to optimise responses. No need to query the database and rebuild the product catalogue JSON every request.

Product catalogue page

Product catalogue page

This is the product catalogue page type. The main point of interest here is the ‘products per page’ field. Our product catalogue will paginate using the value of this field. Setting the value to 0 will display all products on a single page.

AngularJS application

AngularJS application

We manipulate product data on the client-side using AngularJS / SilverStripe templates and a little bit of JavaScript. Controllers.js sends an AJAX request to our backend controller then handles the response. The JSON returned by the controller, is assigned to the $scope.products property, which makes product data (title, description, image) available for use in our templates.

At the core of the product catalogue template is ProductCatalogProductList.ss. Similar to looping over lists in SilverStripe templates, we use the AngularJS directive ngRepeat to loop over our Product data. A number of filters are applied, which limit the number of products shown, change the sort order, and filter products based on their title and description values.

One of the great things about AngularJS is two way data binding. You can bind DOM elements to data models using directives. If applied to a search field, changes to the DOM (user enters a search term) are reflected in that element’s data model, and any changes to the model (autocomplete, search suggestion for example) automatically update the DOM element. This becomes really useful when you use the value of one model, to filter DOM elements, bound to another model. This is what happens in the product catalogue when you search, sort, and paginate Products. Action taken on the UI, updates a data model, which updates the state of another DOM elements.

Having this wiring done behind the scenes, by the framework, is great. Doing it manually in frameworks like Backbone, can be time consuming and lead to performance issues, if you’re not careful.

The pagination template works thanks to a useful SilverStripe requirements feature, and also has a gotcha you should watch out for.

The AngularJS app needs know the number of Products to display per page. Content Authors edit this value in the CMS, but we need to make it available on the client-side. In the ProductCatalogPage.php controller we use SilverStripe’s Templated JavaScript feature to do this. The value is then assigned to $scope.ProductsPerPage in controllers.js which makes it available in AngularJS templates and by JavaScript functions in the client-side controller.

The gotcha when working with AngularJS in SilverStripe templates is the special character ‘$’. Both SilverStripe templates and AngularJS use ‘$’ to prefix variable names. Luckily the workaround is easy, escape AngularJS nested scope variables a backslash ‘\’. There are some examples of escaping AngularJS nested scope variables in the pagination template.


This is a basic example of how SilverStripe can be used to power an AngularJS application. The use-case shown here is a product catalogue but the same setup can be applied to any data you wish to model. If you want to try it out, the example application is available from our addons site


David CraigDavid started out as a print designer creating magazine layouts and working on advertising campaigns. His love of layout and design led to an interest in the web, and how to make it user friendly. Since his shift to the web, David has worked for startups on various projects including marketing sites, campaigns, user interfaces and multi-device web applications. David enjoys discovering new music, brewing beer and looking at well designed things.

Post your comment

Note: Comments are moderated and won't show until they are approved

Comments

  • @James - Thanks for pointing that out, I should have mentioned it in the post, definitely something to watch out for. I've added a comment to the code.

    Posted by David Craig, 4 months ago

  • @Neil - If you've added two products. It could be that your latest product also comes first alphabetically. So it will always appear at the top of the list no matter the sort order.

    Posted by David Craig, 4 months ago

  • We're currently using Angular extensively in a major project under development now (Silverstripe 3.1, Angular, Bootstrap). It's made many parts of the front end incredibly straight-forward.

    There is a Caveat Scriptor around Angular in that its implementation of POST requests is not detected by Silverstripe as Ajax unless the X-Requested-With header is set (as you've done in your controller).

    This caveat caused us a bit of trouble initially.

    All that aside, Angular has enabled us to manipulate some fairly massive datasets client-side with ease allowing for more dynamic pages and fewer page-requests!

    Posted by James Pluck, 4 months ago @CourageWeb

  • Could be me, but your Sort by Latest/Alphabetical isn't working on the example?

    Posted by Neil Berry, 4 months ago @neilberry

  • Thanks for taking the time to post. Installing now!

    Posted by Todd V, 4 months ago @toddvalentine

  • Briliant! Thank you for the tutorial, this is exactly what I wanted to try out!

    Posted by Neil Berry, 4 months ago @neilberry

  • This is cool. We need more posts like this for people to see how versatile SilverStripe is this kind of use cases. What about a web app example next time?

    Posted by Anselm Christophersen, 4 months ago @anselmdk

  • Just a note... to get the requirements for 'bower' (required to fire up the AngularJS app example) you can grab the nodejs package which now includes npm (node package manager) ~ http://nodejs.org/

    Once you have these installed... you can install bower with 'npm install -g bower'. You'll also need git installed so npm can get bower from it's git repo... end result a chain of useful tools.

    You just have to roll through the process to get them...

    Posted by Cam Findlay, 4 months ago @cameronfindlay

  • Thanks for the blog post - keep it up.
    Love that it's a relative simple example, with both code and comments.

    Posted by Thomas Nielsen, 4 months ago @nobrainerweb

  • AnguStripe!!!

    Posted by Uncle Cheese, 4 months ago @unclecheese

RSS feed for comments on this page | RSS feed for all comments

Want to know more about the company that brought you SilverStripe? Then check out SilverStripe.com

Comments on this website? Please give feedback.