Rapid Prototyping with AngularJS

The idea hits you like a lightning bolt. It’s inspiring, transfixing and gripping! You scribble down a design, grab your computer, fire up your tools and… spend the next ours banging your head against a wall of JavaScript as your inspiration slowly drains away.

That’s not right – code should never get in the way of building a great idea.

I’m going to show you a library called AngularJS that can help you get from inspiration to working prototype fast. It’s not designed as a rapid prototyping tool – in fact, it’s a full-featured MVC client-side JavaScript framework designed to allow you to add functionality to HTML… but you can get the marketing spiel elsewhere. Let’s just build an app.

There are a million and one “hello, world” Angular tutorials – hell, I wrote one – but today we’re not going to worry about the really simple stuff, you’re too good (looking) for that. We’re going to jump straight in, and I’ll highlight the interesting bits as we go.

Good to know

This article is about rapid prototyping. That throws a few things out of the window, namely cross-browser compatibility and perfectionism. You’ll find neither here, but that’s ok. We’re just getting something out there. To that end we’ll be using the very latest in web tech: if your browser supports the vh and vw units, you’re good to go.

Photo viewer

We’ll be building a photo viewing app, grabbing photos from any URL and displaying them in a revolutionary new way – a filterable grid! Ok, not too revolutionary, but fun nonetheless.

Here’s our basic gallery page, just in regular ‘ol HTML and CSS:

<!doctype html>
<html>
<meta charset=utf-8>
<title>Photo Viewer</title>

<style>
  * { -moz-box-sizing: border-box; box-sizing: border-box; }
  body {
    font: 17px/1.5 sans-serif;
    background: white; color: black;
    margin: 0; padding: 0;
  }
  h1, h2, h3 { margin: 0; font-size: 1.5em; }
  h1 { font-weight: 100; padding: 0.444em 0.667em; }

  .grid { overflow: hidden; }
  .box {
    float: left;
    height: 33.333333vw;
    width: 33.333333vw;
    position: relative;
    z-index: 10;
    overflow: hidden;
    background: black;
  }
</style>

<h1>Photos, yo.</h1>

<div class="grid">
  <div class="box">
    <img src="//lorempixum.com/400/400">
  </div>
  <div class="box">
    <img src="//lorempixum.com/420/400">
  </div>
  <div class="box">
    <img src="//lorempixum.com/410/400">
  </div>
  <div class="box">
    <img src="//lorempixum.com/420/410">
  </div>
  <div class="box">
    <img src="//lorempixum.com/400/410">
  </div>
  <div class="box">
    <img src="//lorempixum.com/420/420">
  </div>
</div>

The plan is to allow users to add, tag, and search photos.

Angularise

The first thing todo is add Angular to the page. At its most basic, Angular is just one Javascript file, like jQuery. We’ll add it from cdnjs at the bottom of the page.

<script src="//cdnjs.cloudflare.com/ajax/libs/angular.js/1.1.5/angular.min.js"></script>

Next, we add the ng-app attribute to the html tag. When Angular loads it looks for this attribute, and then boots itself into the page.

<html ng-app>

And now we’re ready to use Angular!

Controllers & Scope

The first thing we’ll create is a controller. In Angular these are just regular ol’ Javascript functions. So, at the bottom of the file, add:

<script>

  var PhotosCtrl = function ($scope) {
    $scope.photos = [
      { src: '//farm3.staticflickr.com/2871/9096220194_ff9e60d646_z.jpg', tags: ['bird'] },
      { src: '//farm4.staticflickr.com/3251/3089268872_1869860fbf_z.jpg' },
      { src: '//farm4.staticflickr.com/3049/3088429317_05a0c51605_z.jpg' },
      { src: '//farm3.staticflickr.com/2155/2348877473_ec3768d5d9_z.jpg', tags: ['desert'] },
      { src: '//farm4.staticflickr.com/3044/2348881979_1fd7f979f3_z.jpg', tags: ['valley'] },
      { src: '//farm3.staticflickr.com/2273/2348882083_d8e3e38f89_z.jpg', tags: ['valley'] },
    ];
  }
</script>

Angular will initialise this controller for use if we add to some HTML. This associates an area of DOM with the controller, making it the controller’s responsibility. The area of DOM is called the controller’s scope.

<div class="grid" ng-controller="PhotosCtrl">
  . . .
</div>

Dependency Injection

An important part of Angular is something called dependency injection, and we’ve just seen it in action. You may have been thinking, “where does the $scope parameter come from”? Well, Angular ‘injects’ it by figuring out what the controller is expecting (in this case, $scope). It then goes off and finds an object declared somewhere else called $scope, then hands it back to the controller as an argument.

If you’re interested, it does this by calling toString on your controller function, then uses a regular expression to pull out the expected parameters. Sounds crazy, but it works!

Models & Data Binding

In the controller we’re adding a model called photos to the controller’s scope. That means we can get at the the array of photos in our HTML using a templating language – just as you would with Mustache or any other templating language. All have a src property that’s just a URL, and some have an array of tags. We’ll get to that later.

To list the photos out we use another Angular attribute, ng-repeat.

<div class="box" ng-repeat="photo in photos">
   <img ng-src="{{photo.src}}">
</div>

This turns the .box element into a template for many boxes, and then Angular repeats the template many times – one for each photo object in the photos array.

You’ll also notice the curly braces used – this is out first bit of data binding. As mentioned, Angular has a built in templating language that’s a lot like mustache. But it has an extra feature in that it allows you to bind the value of a model to some text or attribute value in the DOM. That means that as the data in the model changes, so the outputted value changes for the user.

Data binding in Angular is so simple it makes my eyes do the watery thing, but all happy like.

Here the photo’s src property is bound to the src attribute of the image, and if we update the photo’s src property, the image’s src will update too.

To make sure the browser doesn’t try to load an image with the src “{{photo.src}}” when it loads, we also use the ng-src attribute. This allows Angular to only set a src on the image (and therefore trigger the browser to download the image) once it has some data to put there.

Open up this page in your browser (you’ll need to use some kind of server – or try in an online tool like JS Bin) and you’ll find we have some photos repeated in the page – and they’re being dynamically added by Angular! Sweet.

Directives

All these new attributes I’ve introduced you to have a special name in Angular: directives. It’s just a fancy term meaning a new bit of functionality that can be used directly in HTML. We’ll be meeting a few more later on.

Back to the Photo Viewer

You’ve now met all of the most important bits of Angular, and the terminology. Now back to the app!

The next thing we’ll add is some controls for each image, allowing you to alter the URL and tags. Since the .box element is our template, we can add the controls to the template and have it instantly repeated for every photo. Here’s the full box with the controls:

<div class="box" ng-repeat="photo in photos">
  <img ng-src="{{photo.src}}">
  <div class="controls" ng-show="photo.selected">
    <div class="photo">
      <div class="field">
        <label for="url">URL:</label> <input ng-model="photo.src" name="url" id="url">
      </div>
      <div class="field">
        <label for="tags">Tags:</label> <input ng-list ng-model="photo.tags" name="tags" id="tags">
      </div>
    </div>
  </div>
</div>

There’s a few new directives in there: ng-model, ng-show and ng-list.

ng-model sets up two-way data-binding: if the value of the input changes, the model updates. If the model updates, the value in the input changes. Two-way binding is Angular’s speciality.

ng-show is pretty simple: show this bit of DOM if photo.selected is truthy. The value of the directive is an expression, and Angular matches it using something a bit like eval.

The last new directive, ng-list is clever; it binds an array of strings (in the model) to a comma separated list (in an input), allowing you to easily build things like tagging systems. It hooks up to the ng-model directive and add this bit of hotness.

Notice that we never specified that a photo object should have a selected property – Angular figured out that we need it and added it.

To toggle the controls in and out, we’ll use the ng-click directive to toggle picture.selected, and the ng-class directive to specify that when the photo is selected it should have the ‘selected’ class.

<img ng-src="{{photo.src}}" ng-click="photo.selected=!photo.selected" ng-class=" { 'selected': photo.selected }">

This, in combination with some new CSS, will give you a reasonably functional photo viewer!

.controls {
  position: absolute;
  bottom: 1em;
  right: 1em;
  left: 1em;
  padding: 1em;
  color: white;
  background: rgba(0,0,0,.8);
  font-size: 0.667em;
  text-transform: uppercase;
}

.controls .field {
  overflow: hidden;
  margin-bottom: 0.444em;
}
.controls .field:last-of-type {
  margin-bottom: 0;
}
.controls label {
  display: inline-block;
  width: 20%;
  float: left;
  margin: 0;
  line-height: 2;
}
.controls input {
  margin: 0;
  display: inline-block;
  width: 80%;
  float: right;
  background: white;
  border: none;
  font: 1em/1.5 sans-serif;
  padding: 0.298em 0.444em;
}

The controls added inputs for URL and tags. You’ll notice that if you alter the URL of an image, it updates in real time to match. I hope you’ll agree that it was incredibly easy to hook up.

Filter

Next up we’re going to add a filter. This too is incredibly easy in Angular. In fact, there’s absolutely no JavaScript involved.

First the HTML, which I’ve added just after the <h1>, and some more CSS.

<input type="search" ng-model="photoFilter" class="filter" placeholder="Filter…">

.filter {
  z-index: 1000;
  position: fixed;
  display: block;
  top: 1em;
  right: 1em;
  font: 17px/1.5 sans-serif;
  opacity: 0.7;
  -webkit-transition: opacity 100ms linear;
  -moz-transition: opacity 100ms linear;
  -o-transition: opacity 100ms linear;
  -ms-transition: opacity 100ms linear;
  transition: opacity 100ms linear;
}
.filter:hover,
.filter:focus {
  opacity: 1;
}

The ng-model attribute is the important one here – it links the value of the input to a model called photoFilter. Angular provides a way to use the value of a model to filter against an array – it will automatically search all the properties of objects in the array for the value you supply. We can filter the photos with a simple bit of code in the ng-repeat directive:

<div class="box" ng-repeat="photo in photos | filter:photoFilter">

And with that, you can filter the images! Try ‘water’ or ‘valley’ – and add your own tags too.

New photos

Lastly we want to add new photos. To do so, we’ll add button next to the filter that adds a new photo object to the beginning of the photo array. We’ll use the ng-click directive to call one of the controller’s methods. First, the HTML and CSS that I’ve refactored with the filter styles:

<button class="new-photo" ng-click="newPhoto()">+ New Photo</button>

.filter, .new-photo {
  z-index: 1000;
  position: fixed;
  display: block;
  opacity: 0.7;
  -webkit-transition: opacity 100ms linear;
  -moz-transition: opacity 100ms linear;
  -o-transition: opacity 100ms linear;
  -ms-transition: opacity 100ms linear;
  transition: opacity 100ms linear;
}

.filter {
  top: 1em;
  right: 1em;
  font: 17px/1.5 sans-serif;
}
.new-photo {
  font: 0.667em/1.5 sans-serif;
  top: 1.5em;
  right: 16em;
}
.filter:hover,
.filter:focus,
.new-photo:hover,
.new-photo:focus {
  opacity: 1;
}

The last piece is the controller method. It’s just a regular Javascript function added to the $scope, like we did with the photos. This means it can be used anywhere inside the controller’s DOM scope.

$scope.newPhoto = function () {
  $scope.photos.unshift({ src: '//lorempixum.com/500/500' });
};

Scope methods like this are most useful when used with event-handling directives like ng-click, ng-change and ng-submit.

And with that we’ve got a filterable photo gallery up and running pretty darn fast. However, the app’s not the important thing. Angular directives, data binding and templating are the focus – the things that help you get up and running, fast.

Now your turn…

Angular is a great tool for rapid prototyping, even if you don’t end up using it in a real project that goes out to the public. If you like Angular though then it’s perfectly capable of supporting larger scale apps.

There are a number of Angular features I haven’t covered here: routing, AJAX and REST API support, services, the many other kinds of filters and, perhaps most importantly, writing your own directives. Building directives is where the power of Angular lies, but it also has, in my opinion, a steep learning curve. Mastering them, however, unlocks a treasure chest of potential in Angular.

Useful links

The Angular documentation will soon be getting a revamp – right now it’s a little wordy but that’s going to improve. Check out the Developer Guide and the API Reference to explore Angular in depth.

If you enjoy video tutorials, I’d recommend egghead.io, a resource from John Lindquist taking you through Angular from the ground up, and you could also check out my own Tuts+ Course on Angular.

For more wordy articles, check out Year of Moo. I may well also be releasing an article on writing your own directives, so look out for that on the Javascript Playground.

Attribution

Thanks to two, shining.darkness and NeilsPhotography for the photos.

Back to the articles