Custom Development

A Beginner's Guide to Choosing Angular

Adamo Mosca

I have a small desktop application that I wrote awhile ago using C# and Winforms. I am currently rewriting it using HTML, CSS, and JavaScript. Since I'm using web technologies, I figured this is a great way to work with one of the many MV* frameworks available. However, choosing one to work with seems like a daunting task. I checked out TodoMVC to see what developing with each of these libraries would entail. Reading the code of these various frameworks is important but doesn't give me the experience of actually working with them.  Before beginning to code, I narrowed my choices down to Angular and Backbone. I chose these two because Angular is an all in one framework whereas Backbone is an MVC library.

In order to decide which one I'd use, I picked five features of the application that I would write using both Angular and Backbone. The features include displaying data that I retrieve from a web service, showing or hiding rows based on user interactions, adding or removing css styling, populating a selection control for each row of data, and responding to view changes.

Implementing features in Angular 1.3

I stumbled with early development, but after I wrote some code and read tutorials as well as the docs I was able to pickup on using Angular. I know I made a lot of mistakes, but I was able to get the features implemented in a relatively short amount of time. There is a lot of documentation on how to work with Angular. What I didn't realize at first was that a lot of tutorials and blogs I read used $scope.  From what I understand about Angular 2.0, $scope will not be available, but my initial implementation relied heavily on it.  I read this post which explained how to remove the code's dependency on $scope. In addition to removing usages of $scope, the post gave some other good tips on working with Angular.

Another tip I learned from the post is that removal of $scope makes testing easier because you can use plain old Javascript classes. You will not need to worry about wiring up Angular in your tests. A third tip I learned is that using $watch will add overhead because Angular will need to keep track of the $watch. Plus if you do not de-register your $watch then Angular will continue to process it resulting in unneeded processing. The author provides an alternative to using $watch.  

A directive I used multiple times was ngRepeat. ngRepeat cycles thru an array creating a new HTML element for each model in the array. Using the mustaches (i.e. double curly braces), I was able to inject the value of the model into the HTML.

<div ng-repeat="model in models"></div>

The above code cycles through all the models listing their name in a div container.

I retrieved my models using a factory that is called from my controller. You may be wondering why I didn't use a service. I used a factory based on my readings. From my understanding, there are subtle differences between a service and a factory, but both do the same thing. I don't have any practical reasons for using factories over services at least in my initial observations. I read about factories first and was able to successfully implement one. Afterwards, I read about services, but since I had the factory working, I didn't see a reason to change to a service. 

Using ngRepeat again I was able to load data into a selection control. I did some additional research that led me to ngOptions. According to Angular's documentation, ngOptions provides a couple benefits such as performance, and flexibility with the model. Being that I do not load much data into the selection control, I did not see a reason to change from ngRepeat.

Another directive I incorporated into my application is ngChange. Using ngChange I can bind a function to the directive. When the user makes a change, the function is executed. When using ngChange, the ngModel needs to be set.

<input type="checkbox" ng-model="showOption" ng-change="show(showOption)">

I also used ngClass in order to apply CSS classes to my HTML elements. There are multiple ways to apply CSS classes. In my case I had a boolean field on my model. When the boolean field evaluated to true, the CSS class was applied. When set to false, then the CSS class was removed.

<div ng-repeat="model in models" ng-class="{'css-class': model.attribute}">

Using ngShow allowed me to show or hide rows that I created with ngRepeat. Binding a function in my controller to ngShow, if the function evaluated to true then the row is displayed, otherwise its hidden. Angular also has ngHide which does the opposite of ngShow. I decided to use ngShow over ngHide because my application will always display the rows until an attribute is false. Thus true will show the row and false will hide the row. This is much easier for me to understand than if I used ngHide. If I used ngHide then true will hide the row and false will show the row. This, to me, seems backwards since I will initially be showing all the rows.

<div ng-repeat="model in models" ng-show="showModel(model)" ng-class="{'css-class': model.attribute}">

Implementing features in Backbone 1.1.2

Similarly with Angular, I stumbled at early development with Backbone, but after reading the documentation and looking over the TodoMVC project, I was able to get my features working. The first task was to create a model which would represent a row of data on the web page. Next I created a collection to hold a set of my models. Lastly I created two views. One view to represent what a row of data will look like. The other view represents what the entire page will look like.

var Model = Backbone.Model.extend({...});

var ModelCollection = Backbone.Collection.extend({...});

var ModelView = Backbone.View.extend({...});

var ModelListView = Backbone.View.extend({...});

In order to get my models onto the web page, I created a collection of models. From here I injected the collection into the main view of my web page. I developed a render function to cycle through the collection and render each model according to a template I defined.

In order to populate the selection control, I had to create another collection then assign it to each model. Thus each model in my collection had another collection. This didn't seem like an optimal solution. I followed the same code as I did with the above code, I created a model, then I created a collection. I didn't need to create a view. Instead, inside the template I cycle through each item adding it to the selection control.

In order to respond to a change in the selection control, I had to set up events withing my ModelView. In the case of the selection control, I bind a function to the control's change event. When the selection is changed the function bound to the change event is executed.

var ModelView = Backbone.View.extend({  
  events: {
    "change #selectionControlId": "selectionChangeEvent"
  },

}

To add/remove CSS classes to the HTML elements, you need to call "addClass()" or "removeClass()" and pass in the name of the CSS class you want to add or remove. Adding and removing classes is not a concern of Backbone. They are jQuery functions. Unlike Angular, Backbone is a MVC library. Therefore, getting functionality like DOM manipulation and two-way data binding requires the introduction of other libraries

Also, Backbone doesn't concern itself with showing or hiding HTML elements. You can use jQuery for this. I didn't use jQuery but instead using Underscore's filter function I created a function in my collection to return a subset of models. Then I rendered the subset on the web page essentially wiping out the existing data on the page and replacing it.

Angular or Backbone

Although I have some web development experience, I still consider myself a novice. I decided to finish my application using Angular for the reasons stated below.

  • I like how I was able to leverage Angular's directives to maintain single responsibility. For instance, I set up the ngChange to execute a function when the selection control changes. I set up the ngShow directive to show or hide HTML elements. I set up the directives so that it executed a function that performed a single responsibility.
  • I like two-way binding so that I don't have to manually re-render the data when the data changes.
  • Angular provides a lot out of the box. Some features that Angular includes are dependency injection, two-way binding, and templating.
  • I like working with Javascript objects. When I needed to retrieve a value from the model using Backbone, I always tried "model['attribute']". That doesn't work because with a Backbone model you need to retrieve the value by writing "model.get('attribute')"
    • Also I kept making the following mistakes with Underscore:  I would attempt to iterate an array by doing "array.each(function())". That didn't work. I had to do "_.each(array, function())"
    • Conversely with a collection I can do "collection.each(function())" but not ".each(collection, function())"
  • Based on the features I developed, using Angular resulted in writing less code.
  • I know "this" in Javascript is tricky. Using Backbone I would attempt to retrieve a value from the model using "this.model.get()" but that sometimes didn't work. I had to add "var self = this" at the top of the function. That tripped me up a few times. I read that you should also do that with Angular, but it was not as apparent with Angular as it was with Backbone.

I still have a lot to learn to with web technologies. Angular provides a lot more features (e.g. custom directives, filters) than what I've described in this post. I plan to keep learning Angular by incorporating various Angular functionality into my application.

Adamo Mosca
ABOUT THE AUTHOR

Technical Consultant