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 thatjs
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 row
s. 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!
Comments