Enhancing Web Apps with AmplifyJS

Enhancing Web Apps with AmplifyJS

Tutorial Details
  • Topic: AmplifyJS
  • Difficulty: Intermediate
  • Estimated Completion Time: 45 min

There seems to be a new crop of special-purpose JavaScript libraries every week. Gone, it seems, are the days of using only one library per project. Today I’ll introduce you to a very cool component library, AmplifyJS, that offers just a few very specialized components.


Devs, Meet AmplifyJS

According to the website:

AmplifyJS is a set of components designed to solve common web application problems.

Sounds prestigious, but what’s actually in this library?

AmplifyJS has three main pieces:

  • An AJAX API
  • A PubSub Event System
  • A Client-side Storage API

Join me now for a tour of the incredible AmplifyJS library! We’re going to build a super-simple employee tracker; really, it’s just a table with a few app-like features, courtesy (partly) of AmplifyJS.

We don’t really need to concern ourselves with styling and layout issues today so I’m going to use the Twitter Bootstrap library. It’s incredibly simple: just include the link to the CSS file—which they let you hotlink from Github—and you’re in business.


Step 1: Setting it Up

So, make yourself a project directory. Start with the index.html file, and a js folder. Now, head over to the AmplifyJS website and click that huge, red “download” button. Once, you’ve got the library zip, extract it, and move it into the js folder. We’re going to need a few other things as well:

  • jQuery: Amplify’s AJAX component uses jQuery’s AJAX feature underneath it’s API, at least by default. But we’ll be using jQuery for other stuff, so bring it on in.
  • bootstrap-modal.js: The Twitter Bootstrap library includes a few scripts for getting all interactive. And we’re going to use one: the modal window jQuery plugin. Download it, and add it to that js folder.
  • There are two other scripts that I’ll mention along the way, but these we’ll write ourselves.

Then, start off our index.html file like this:

<!DOCTYPE HTML>
<html>
  <head>
    <title>AmplifyJS</title>
    <link rel='stylesheet' href='http://twitter.github.com/bootstrap/1.3.0/bootstrap.min.css' />
  </head>
  <body>
    <div class='container'>
      <div class='row'>
        <div class='span16' id='alert-area'>
        </div>
      </div>
      <div class='row'>
        <div class='span4'>
            <h2>Commands</h2>
        </div>
        <div class='span12'>
        	<h1>Employees</h1>
        </div>
      </div>
    </div>
    <script src='https://ajax.googleapis.com/ajax/libs/jquery/1.6.2/jquery.min.js'></script>
    <script src='js/amplify/amplify.min.js'></script>
    <script src='js/bootstrap-modal.js'></script>
  </body>
</html>

If you aren’t familiar with using Twitter Bootstrap, you’ll see it’s no sweat to use. We’ve got a container that is 940px wide. Then, we have two rows. The first has one column, that covers all 16 columns. The other has two columns: one is 4 columns wide, and one is 12 columns wide.

One more thing, before we get to some real coding: we’re going to pop up a modal window that allows up to input employees. Under the <div class='container'>, add this modal window HTML. Yes, it seems like a lot code, but it’s mainly Bootstrap stuff:

<div id='add-employee-modal' class='modal fade'>
  <div class='modal-header'>
    <a href='#' class='close'>x</a>
    <h3>Add an Employee</h3>
  </div>
  <div class='modal-body'>
    <form id='employee-form'>
      <div class='clearfix'>
        <label for='firstName'>First Name:</label>
        <div class='input'><input type='text' name='firstName' placeholder='John' /></div>
      </div>
      <div class='clearfix'>
        <label for='lastName'>Last Name:</label>
        <div class='input'><input type='text' name='lastName' placeholder='Doe' /></div>
      </div>
      <div class='clearfix'>
        <label for='role'>First Name:</label>
        <div class='input'><input type='text' name='role' placeholder='Designer' /></div>
      </div>
    </form>
  </div>
  <div class='modal-footer'>
    <button id='create-employee' class='btn primary'>Add</button> 
  </div>
</div>

All right, we’re ready to go! Let’s code.


Step 2: Wiring the Modal Window

Open up a script tag at the bottom of index.html (I’m just doing this inline, but feel to put it in a new JS file). start this way:

	(function () {
		var employeeModal = $('#add-employee-modal').modal({ backdrop: 'static' });

	}());

We’re using the Bootstrap modal plugin here; this just “instantiates” the modal window. Now, we want the window to appear when we click the “Add Employee” button. Of course, we’ll have to add the button first: put this in the <div class='span4'>, right under the <h2>.

	<p><button id='add-employee' data-controls-modal='add-employee-modal' class='btn'>Add Employee</button></p>

That data-controls-modal='add-employee-modal' attribute will display the modal with said ID when the button is clicked.

So, the user will need to fill in the form, click the “Add” button which has an id of create-employee. So, let’s wire up a click event handler for the button:

$('#create-employee').click(function () {
    var form = $('#employee-form');
    employeeModal.modal('hide');
    EMPLOYEE.create(
        form.find('[name=firstName]').val(), 
        form.find('[name=lastName]').val(), 
        form.find('[name=role]').val()
    );
    form.find('input').val('');
});

We get the form, and then hide the modal window. Then, we’re going to call an EMPLOYEE.create method, passing the first name, last name, and role as the three parameters. Finally, we clear the form.

amplify.publish

But wait, you say, what’s EMPLOYEE.create? Well, it’s a micro-“class” that I’ve put in js/employee.js. Check it out:

var EMPLOYEE = {
    create : function (firstName, lastName, role) {
       var employee = {
            firstName: firstName,
            lastName: lastName,
            role: role,
            dateEmployed: new Date()
       };
       amplify.publish('employee-created', employee );
       return employee;
    }
};

You’ll want to throw a script tag for it up with the others.

Pretty simple, right? We just create an object literal with our parameters, and add a dateEmployed property. But, then—and finally!—we have the first entrance of the AmplifyJS framework. Here, we’re using the pub/sub events component. This is great for doing loose coupling between parts of your app.

This method doesn’t have to know if another part of our code wants to do something with each new employee we create; Our “Add” button event handler doesn’t have to worry about it. We’ll just publish it as an “employee-created” event for any part that is interested to take. We pass our new employee object as data for anyone interested. Then, we return the employee object (even though we don’t keep track of it in our event handler).


Step 3: Reacting with amplify.subscribe

So, is any other part of our app interested in the “employee-created”? Yes, in fact. We want to do two things. First, add this employee to a table on our page. Second, we want to store the employee in localStorage. Here’s the first part of that:

  amplify.subscribe('employee-created', function (employee) {
    employeeTable.add([employee.firstName, employee.lastName, employee.role, employee.dateEmployed]);
    newAlert('success', 'New Employee Added');
  });

To subscribe to an event, we call amplify.subscribe. We want subscribe to the “employee-created”; when that events occurs, we want to add it to the employeeTable; notice that instead of just passing it the employee object, we “convert” it to an array; this is because we need to be sure the elements will be in the right order. Then, we want to display an message, letting our user know that the employee was added successfully.

What’s up with this employeeTable variable? Well, first, we have to add the <table> to our document. So, underneath our “Employees” <h1>, add this:

<table id='employee-table' class='zebra-striped'>
    <thead>
        <tr>
            <th> First Name </th>
            <th> Last Name </th>
            <th> Role </th>
            <th> Date Employed </th>
        </tr>
    </thead>
    <tbody>
    </tbody>
</table>

Now, we have to capture this table as a variable up in our var statement at the top:

employeeTable = TABLE.create($('#employee-table')),

And TABLE? That’s the last piece of JS for this puzzle. Put this in js/table.js and don’t forget the script tag:

var TABLE = {
    proto : {
        init : function (el) {
            this.element = $(el).find('tbody'); 
        },
        add: function (arr) {
            var row = $('<tr>').html(function () {
                return $.map(arr, function (value) {
                    return '<td>' + value + '</td>';
                }).join('');
            });
            this.element.append(row);
        },
        load: function (rows, order) {
            for (var i = 0; rows[i]; i++ ) {
                this.add(rows[i]);
            }
            var fields = [];
            for (var j = 0; order[j]; j++) {
                fields.push(rows[i][order[j]]); 
            }
                this.add(fields);
        },
        clear: function () {
            this.element.empty();
        }
    },
    create : function (el) {
        var table = Object.create(this.proto);
        table.init(el);
        return table;
    }
};

It’s a bit complicated, but you should have no problem grokking it. We’ve got a proto property that is the prototype for our table instances. Then, when we call create, we use Object.create to create an object that inherits from this.proto. After that, we call the init method to set any properties. Finally, we return the table instance.

This micro-API makes it easy for us to work with our table. You should be able to see how passing an array to the add method will add a row to our table. Notice also that we can pass an array of rows to load and fill the table up; we’ll use this soon.

Oh, then there’s the newAlert method we called:

function newAlert (type, message) {
    $('#alert-area').append($('<div class='alert-message ' + type + ' fade in' data-alert><p> ' + message + ' </p></div>'));

    setTimeout(function () {
        $('.alert-message').fadeOut('slow', function () { this.parentNode.removeChild(this); });
    }, 2000);
}

As you can see, this just simply adds a div inside out <div id='alert-area'>; the new div takes advantage of the Twitter Bootstrap alert styling; after two seconds, we fade the alert out and remove it.

amplify.store

But that’s not the only think we want to do when the “employee-created” event occurs:

employeeStore = amplify.store('employees') || [];

At the top, with our two other variables, make the third and final one: employeeStore. If amplify.store('employees') returns something, we’ll use that; otherwise, we’ll use an empty array.

amplify.subscribe('employee-created', function (employee) {
    employeeStore.push(employee);
    amplify.store('employees', employeeStore);
});

Now we’re using the storage component of AmplifyJS. It really couldn’t be simpler: to store a value, pass amplify.store a key and the value. To retrieve the value, hand it the key. Underneath, AmplifyJS is storing that key and value in whatever storage type is available on that browser.

So here, we add a new employee to the array and store the array in the “employees” key. I should note that since we’re storing an array, AmplifyJS is using JSON serialization to convert that array to a string. Therefore, if you’re trying to support browsers without native JSON support (IE 5 and down, Firefox 3 and down), you’ll want to include the json2.js library.


Step 4: Saving to the Server (with amplify.request)

In our little app-example, we’re saying that by default, the data you put into the app is kept only on your computer (in that one browser). However, if the user wants, we’ll allow them to put it up on the server (hypothetically, this is private information they might not want to share; however, if they want to access it from other devices, they could do this.).

We’ll start by adding a button for uploading the data.

<p><button id='push-data' class='btn'>Push Data to Server</button></p>

Now, of course, your brilliant minds have already figured out that we’ll be using AmplifyJS’s AJAX component. amplify.request is an incredibly flexible API, and we won’t be looking at everything it can do. However, you’ll get a good feel for how it works here.

Doing AJAX with AmplifyJS is a bit different than with other libraries: the idea is that first you define a connection to the server; then, you can use that connection any number of times after that. Let’s begin by defining a connection, called a “resource” by AmplifyJS:

amplify.request.define('pushData', 'ajax', {
    url: 'data.php',
    type: 'POST'
});

The first parameter here is resourceId, which we’re setting as “pushData”; this is how we’ll refer to our connection when we’re using it. The second parameter is the request type; in this case, “ajax.” This is the only request type built into AmplifyJS; you can add your own, but this is suitable for our needs today.

Finally, we have an options object. According to the documentation, your settings options are anything you would set in jQuery.ajax, as well as cache (which allows you to set up a custom memory cache) and decoder (for parsing the AJAX response). In our case, only two options are necessary: the url, and the type of request we’re making.

Of course, we’ll need some simple PHP on the back end; make sure the data folder is writable.

data.php

 <?php
   $employees = json_encode($_POST['employees']);
   $file      = fopen('data/data.json','w+');
   fwrite($file, $employees);
   fclose($file);

   echo 'success';
?>

Now, how about using the connection, the resource, we’ve defined? Well, let’s do this in a click handler for that <button id='push-data'>:

$('#push-data').click(function () {
    amplify.request('pushData', { employees: amplify.store('employees') }, function (data) {
        amplify.publish('data-pushed', data);
    });
});

When using the resource, the first parameter is the resource ID; it’s the same resource ID we have the resource we defined, so AmplifyJS knows which to use. Second, we pass data hash. In this case, we pass the content in our store, under the key “employees.” The final parameter is a function that’s called when we get a response.

Once we get a response, we’ll publish the “data-pushed” event. Then, we’ll just alert the user that it worked:

amplify.subscribe('data-pushed', function () {
    newAlert('success', 'Data successfully sent to server');
});

Taking it a Step Further

Well, that’s our little example app. We’ve looked at using all three of AmplifyJS components: amplify.publish / amplify.subscribe, amplify.store, and amplify.request. We’ve covered pretty much all there is to know about the pubsub and store parts (there is a bit more!), but there’s a lot more you can do with the request API. So, go check out the website to learn more!

So, what are your thoughts on AmplifyJS? Like it? Find it too redundant? Let’s hear it in the comments!

Note: Want to add some source code? Type <pre><code> before it and </code></pre> after it. Find out more
  • kankuro

    nice tuts… very clear and explain will… by the way, it seems that this page is crappy.. the adds on the right side of the page goes to the bottom… please check it out… :D

  • http://thetechtime.com rax

    Awesome script !
    use of JSON is also great !! :)

  • http://baliniz.com Baliniz

    Interesting js framework..
    hope it have better ajax performance than another big js frameworks :)

  • http://mattonik.sk Martin Puškáč

    Nice tutorial. I was looking at AmplifyJS for a while.

    I used it’s store functions for one of my project with TaffyDB for MySQL like engine on client side. Really interesting JavaScript library.

  • http://www.startutorial.com XuDing

    Thanks for this useful tutorial.

    I have found Bootstrap very useful also.

  • http://www.symetronapps.com luka

    the right side bar is kind of screwed up, i think the admin should check it out.

  • http://coderbay.com/ coderbay

    good tutorial

  • PixelPusher

    Your first sentence hit the nail on the head. I’m still trying to locate the conveyor belt off of which all these JS llibraries and frameworks must be dropping. I’m not really into making apps so much as typical sites, so they’re not a huge issue for me, but it still feels like way too much to keep up with.

  • http://inelmo.com LilOrange

    This is a great tutorial, Java Script is a way to go ))

    P.S I’m not sure if it’s a problem on my side, but on this particular page a sidebar is moved towards the bottom. Just so you know )))

  • http://oddnetwork.org haliphax

    I think I’ll just stick with jQuery and use pubsub/local storage plugins like these:

    http://plugins.jquery.com/project/jStore
    http://plugins.jquery.com/project/PubSub

    That way, I can stick with “just one library”. :)

    • http://gregpettit.ca Greg

      jQuery + 2 plugins (scripts) vs. jQuery + 1 data interchange library (script… uses jQuery)

      I don’t see the difference except for semantics. Call Amplify a “plugin” and now your set of things to include is less by one.

  • http://rommelcastro.me Rommel Castro A

    i have to read this and try!

  • http://andrewburgess.ca Andrew Burgess
    Author

    Thanks everyone!

    One thing I forget to mention in the tutorial is that you’ll want to load the data from the storage when the page is loaded. Here’s how you’d do that:

    var employeeArray = [];

    for (var i = 0; employeeStore[i]; i++ ) {
    var e = employeeStore[i];
    employeeArray.push([ e.firstName, e.lastName, e.role, e.dateEmployed]);
    }

    employeeTable.load(employeeArray);

    In the downloadable code, this’ll just be `employeeTable.load(employeeStore)`. This works, but it’s not technically correct, because if relies on the object’s keys being in the right order (you shouldn’t expect that). What you see above is better.

    Thanks again!

    • srigi

      Realy good and useful tutorial, thanks. I like your way of emulating classes in JS (EMPLOYEE and TABLE). But you should definitely check how CoffeScript or Google Closure is solving this. It would be also nice, if you publish project at Github, so anyone can contribute to this little demo.

      For example, pressing #publish-data should IMHO also raise pub event, and storing should be handled by some subscriber.

    • ben

      I get this error “Uncaught TypeError: Cannot read property ’0′ of undefined” on line 19 of table.js when I add your code
      var employeeArray = [];
      for (var i = 0; employeeStore[i]; i++ ) {
      var e = employeeStore[i];
      employeeArray.push([ e.firstName, e.lastName, e.role, e.dateEmployed]);
      }
      employeeTable.load(employeeArray);

      You are not passing the order parameter to the table.js load method. What should be passed as a value?

  • Gavin

    Thanks for this, pretty awesome. Super small error in the tutorial – the modal form has the label First name for role.

    Thanks again

  • http://gregpettit.ca Greg

    Haven’t had the time to go through the whole tutorial yet, but one thing was interesting off the top: it uses jQuery’s .ajax by default. Since Zepto.js also has a $.ajax() function, I wonder if Amplify.js is also compatible with Zepto by default? Possibly not, if they use jQuery.ajax() instead of $.ajax(). I think I’ll find out when I return to this tutorial in earnest. ;-)

    A bit disappointed that it’s just AJAX; it seems like Amplify.js would be a great place for Websockets, too.

  • http://ayublin.com Ayub Lin

    This is really a good introduction to AmplifyJS, and I didn’t aware of twitter bootstrap before. Thanks for the two in one introductory tutorial :D

  • http://tween.ir/ Hassan

    So basically publish/subscribe is like WP’s action filters, right?

  • Jonas

    Great article.
    To make the part with inserting rows into a table work in IE7-8 as well, I changed

    var table = Object.create(this.proto);

    to

    if (typeof Object.create !== ‘function’) {
    Object.create = function (o) {
    function F() {}
    F.prototype = o;
    return new F();
    };
    }

    Hope this helps someone.

  • Raghu

    Here is on more interesting script to upload files to server!!

    Do it asyncronously with asp.net and jquery!!
    http://www.msguy.com/2011/11/image-upload-using-jquery-uploadify.html

  • http://s-vizion.com Shawn Crigger

    I just wanted to say thanks for a short, and to the point guide on using Amplify, it’s a great pub/sub library with the added bonus of local storage also. very interesting method of making classes in JavaScript also. I’m personally trying to figure out how to replace the Table Class with a JS Template Library as I need something similar for a project. Anyway thank you for the nice short and simple guide.

  • http://www.erikphipps.com Erik Phipps

    Does anyone know of a large site that uses amplify.js? I’d like to dig into some well structured/written code that goes beyond this tutorial. I looked at the amplify and some of the appendTo sites, but they don’t seem to use amplify.

  • http://onnet.su Kirill

    Hi Erik

    Take a look at portal.2600hz.com
    It uses AmplifyJS
    It is cloud telephony service platform, so you’ll need to register

    Best,

  • http://twitter.com/mspanish Stacey Reiman

    Great tutorial, helped me get going with amplify.js. One thing I’m just starting to research now – how am I to bring up an individual employee to delete, if they all have the same key of ‘employee’? I guess I can run a filter loop or something but if anybody knows how to apply a “delete” option to this tutorial I’d be super thankful!