This lesson covers:
The form is nothing to complicated, mainly so you can go in and edit it as you want. If you know your html pretty well, you can add whatever you want to it, and the server will save it automatically.
I have fallen in love with bower which allows you to quickly add all the libraries you need. Components are nice, but they are designed around a phylosophy that frowns apon large libraries. A good thing to look into, but not currently as popular. We will touch on components later, but for now lets get started with backbone.
Anyways, get to your folder in your terminal and install jquery, underscore, and backbone with this:
$ npm install -g bower
$ bower install backbone
$ bower install jquery
Just as a little side note, there is a little magic happening behind the scenes. There is a .bowerrc file that tells bower where to get the files and where to put them.
Stoping a http form from going forward is just like preventing the default from any other element event.
$("#form").on('submit', function(e) {
e.preventDefault();
});
Another option is to put “return false;” at the bottom of the callback function, but I find it a little easier to read by putting “e.preventDefault()” right at the top.
Now we need to make our own request, but this time with ajax. I am going to use $.ajax(), but $.post(), will also work. $.ajax is much more flexible, and it’s good to learn all the extra settings that are used.
$.ajax({
type : "POST",
url : "/products/create",
data : $("#form").serialize(),
success : function(res) {
// all done
}
});
Now we need to clear the form…
$("#form").each(function(){
if(this.reset) this.reset();
});
… and update the total counter…
$.ajax({
type : "GET",
url : "/products/total",
success : function(total) {
$("#total").text(total);
}
});
All together, the javascript for this page looks like this.
$("#form").on('submit', function(e) {
e.preventDefault();
$.ajax({
type : "POST",
url : "/products/create",
data : $("#form").serialize(),
success : function(res) {
console.log('response:',res);
$("#form").each(function(){
if(this.reset) this.reset();
});
$.ajax({
type : "GET",
url : "/products/total",
success : function(total) {
$("#total").text(total);
}
});
}
});
});
But this is ugly. Its hard to reuse any of this code, the flow is not easy to read, and it does not efficiently use jquery.
First, lets cache some of our jquery DOM lookups.
var $form = $("#form");
$form.on('submit', function(e) {
e.preventDefault();
$.ajax({
type : "POST",
url : "/products/create",
data : $form.serialize(),
success : function(res) {
$form.each(function(){
if(this.reset) this.reset();
});
$.ajax({
type : "GET",
url : "/products/total",
success : function(total) {
$("#total").text(total);
}
});
}
});
});
We now only search through the DOM once, for the form. We are using an id, which is pretty quick, but if we had to use a class, or a more complicated search, it would save time, which is noticable for larger js applications. I did not cache $(“#total”) because we only use it once, but if we needed to access it again, it would be good to cache that also.
Now lets break up the callbacks. We can do this a couple ways.
var $form = $("#form");
$form.on('submit', function(e) {
e.preventDefault();
var GETCallback = function(total) {
$("#total").text(total);
};
var POSTCallback = function(res) {
console.log('post callback');
$form.each(function(){
if(this.reset) this.reset();
});
$.ajax(GET);
};
var GET = {
type : "GET",
url : "/products/total",
success : GETCallback
};
var POST = {
type : "POST",
url : "/products/create",
data : $form.serialize(),
success : POSTCallback
};
$.ajax(POST);
});
This breaks up the pyramid look code often gets when using asynchronous calls. It’s still a little hard to follow.
var $form = $("#form");
$form.on('submit', function(e) {
e.preventDefault();
var totalRequest = {
type : "GET",
url : "/products/total"
};
var updateTotal = function(total) {
$("#total").text(total);
};
var setRequest = function() {
return {
type : "POST",
url : "/products/create",
data : $form.serialize()
};
};
var clearForm = function(form) {
$form.each(function(){
if(this.reset) this.reset();
});
};
$.ajax(setRequest())
.success(clearForm)
.success(function() {
$.ajax(totalRequest)
.success(updateTotal);
});
});
Now we are getting better. We have setup all of our data that we need, and seperated that from the logic. Lets see if we can make it a little more object oriented.
var createPage = {};
createPage = {
$form : $("#form"),
totalRequest : {
type : "GET",
url : "/products/total"
},
setRequest : function() {
return {
type : "POST",
url : "/products/create",
data : this.$form.serialize()
};
},
updateTotal : function(total) {
$("#total").text(total);
},
clearForm : function() {
this.$form.get(0).reset();
},
handleSubmit : function(e) {
e.preventDefault();
$.ajax(this.setRequest())
.success(this.clearForm.bind(createPage))
.success(function() {
$.ajax(createPage.totalRequest)
.success(createPage.updateTotal);
});
},
initialize : function() {
this.$form.on('submit', this.handleSubmit.bind(createPage));
}
};
createPage.initialize();
Wow, that was a big change. We now have everything wrapped into one object. This allows us to do two things:
1. the object requires a specific structure that cleans up the code
2. we are now able to use “this” inside the object to refer to createPage
There is a downside and it is mostly related to the way jQuery sets up success callbacks. By default jQuery sets the context of callbacks to the jQXHR, which is the object with information on the request. There are two ways to get around this, use .bind (like I did in the example) or set the context in the options you pass $.ajax. I have had better luck with .bind.
If you are not used to this much structure it can feel weird, and you are probably asking “why are we doing this?”. I will explain more later.