Notes on AngularJS

angularjs

Most of AngularJS is straightforward and there’s good documentation elsewhere online.

Some important/interesting bits 

  • filters are very cool e.g. {{ lastname | uppercase }}. Particularly useful with ng-repeat e.g. ng-repeat="x in names | orderBy:'country'" or ng-repeat="x in names | filter : 'i'" . Wham! So convenient. And you can write your own filters.
  • ng-src for images
  • ng-bind is one-way binding ($scope to view); ng-model is two-way binding.
  • easy form validation with using the required attribute, .$valid or .$error​, and possibly some cool CSS magic using ng-dirty/pristine/valid/invalid. Good to disable default browser (novalidate) validation to have consistency.
  • when working with tables, there are handy properties like $odd , $even, $index you can use, say, with ng-if
  • creating dropdown lists connected to a model is easy with ng-options (while you could also use ng-repeat, with ng-options the objects don’t have to be strings)
<select ng-model="selectedName" ng-options="x for x in names">
</select>
// or using any Object, where x is the key, y is the value.
<select ng-model="selectedCar" ng-options="x for (x, y) in cars">
</select>
  • angular events could be used for some pretty cool stuff with animation
  • ng-include lets you refactor out snippets of html, which is loaded via ajax
  • consider using a custom directive instead of ng-include – makes the HTML more expressive.
  • custom directives can be of type element, attribute, class, or comment. Default is element and attribute (i.e. restrict: 'EA').
  • you can move controller logic into a custom directive using the returned object’s controller property.
app.directive("productDetails", function() {
   return {
      restrict: 'E',
      templateUrl: 'product-details.html',
      controller: function(..){/*controller logic can be moved here*/},
      controllerAs: 'someAlias'
   };
});
  • $scope belongs to the controller, $rootScope is for the whole app.
  • while ng-init lets you initialize some values, should really think whether this initialization belongs in a controller.
  • there are angular equivalents (as services that start with $) of native things like window and location – and it’s best practice to use these angular services. You can write your own services.
app.service('hexafy', function() {
   this.myFunc = function (x) {
      return x.toString(16);
   }
});
  • cannot call this inside the success call on $http service to refer to the containing controller’s this. Makes sense.
  • angular handles asynchronicity using promises (so no callback hell).
  • config(..) runs before run(..), which runs before controller(..).
  • remember to use closure for javascript modules, good practice.

Thinking about MVC and TDD in AngularJS

AngularJS lends itself very well to an MVC approach.

Keep the view stuff in the HTML, the controller logic in .controller(..)s, and the model (likely tied to a backend service/database) in variables in the angular module (bound to the view with the intention of exposing the minimum information needed).

Split view/controller/model components so that each model entity (e.g. product) corresponds to isolated controller(s) (e.g. productController), and view snippets (e.g. productsList HTML element or custom directive).

This way each component has a small focus of what it is trying to do and it can do it well. This also makes it easier to test-drive the application, small careful steps.

Modularity and testability can be further improved by using proper Angular services (e.g. $window, ​$location instead of the native elements). Using dependency injection, you can inject mock objects and check that the methods you expect are being called on the injected (mock) services in unit tests.

A simple SPA game with AngularJS and ASP.NET Web API 2

This is a simple single page application (SPA) game which has a AngularJS (1.x) front-end talking to a ASP.NET Web API 2 back-end. This is in the initial stage and there’s plenty to improve (see end of this article).

How the game works

Player 1 sets a word for player 2 to guess. This word is sent to the server, which returns a unique game key. This key is manually given to player 2 who uses it to retrieve the word they are supposed to guess (masked on the UI).

This slideshow requires JavaScript.

Under the hood

Player 1 sends a HTTP POST request with the word they want player 2 to guess to the server. The server returns JSON data with a unique game key, which player 2 then uses to retrieve the word (masked) that they should guess. Player 2’s guesses are handled client-side using AngularJS.

gtwuml1

A few key code snippets.

Sever-side: A very simple API. A POST request handler that puts the new word in the database and generates a corresponding unique game key; and, a GET request handler that returns the underlying target word to guess for a given unique game key.

Client-side: AngularJS script to handle client-side player 2 gameplay.

The code that updates the state of the guessed string given a new character guess.

And the corresponding unit tests (using QUnit)

Of course, this is in the initial stages and there’s much to improve, including the following:

  • Currently, the entire word that player 2 is supposed to guess comes to their client. Player 2 could easily retrieve this word (and cheat!) using dev tools in their browser. A solution would be to do the checking – of whether the candidate letter that player 2 entered occurs in the target – on the server-side.
  • Plenty of user interface improvements. For example, after player 2 successfully guesses the word, the input box and “check” button should be hidden. Could be easily with ng-hide.
  • Player 1 doesn’t, currently, have a way of being notified when Player 2 finishes the game. This could be done using server-to-client messaging using SignalR.

You can find the full code on GitHub.