Created
September 14, 2012 21:05
-
-
Save sahinsf/3724817 to your computer and use it in GitHub Desktop.
jQuery to Backbone step by step
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
<?php | |
//if(isset($_POST['text']) && !empty($_POST['text'])) | |
//$text = $_POST['text']; | |
//$text = array("text" => $text); | |
$text = json_decode(file_get_contents('php://input')); | |
//$text -> text .= " said user!"; | |
print(json_encode($text)); | |
?> |
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
<!DOCTYPE html> | |
<html> | |
<head> | |
<meta charset='UTF-8'> | |
<title>HTML Document</title> | |
<link href="http://fonts.googleapis.com/css?family=Abel" rel="stylesheet" type="text/css"> | |
<style type="text/css"> | |
body { padding: 0; margin: 0; background-color: #fff; } | |
h2 { font-family: Abel, sans-serif; margin: 0; padding: 0 0 5px 0;} | |
input { background-color: #ddd; border: 0; } | |
input:active { background-color: #bbb; } | |
#new-status { margin: 20px; padding: 20px; background-color: #67A9C3; } | |
#statuses { margin: 20px; padding: 20px; background-color: #92B456; } | |
</style> | |
<script src="//ajax.googleapis.com/ajax/libs/jquery/1.8.1/jquery.min.js"></script> | |
<script src="underscore.js"></script> | |
<script src="backbone.js"></script> | |
</head> | |
<body> | |
<div id="new-status"> | |
<h2>New monolog</h2> | |
<form action=""> | |
<textarea></textarea><br> | |
<input type="submit" value="Post"/> | |
</form> | |
</div> | |
<div id="statuses"> | |
<h2>Monologs</h2> | |
<ul></ul> | |
</div> | |
<script > | |
/* | |
$(document).ready(function() { //wait for DOM to load (listen page event) | |
$('#new-status form').submit(function(e) { //set a submit listener (listen user event) | |
e.preventDefault(); | |
$.ajax({ //send input to the server | |
url: 'ajaxStatus.php', | |
type: 'POST', | |
dataType: 'json', | |
data: { text: $('#new-status textarea').val() }, | |
success: function(data) { //listen network event | |
//parse the response | |
$('#statuses ul').append('<li>' + data.text + '</li>'); // HTML templating | |
$('#new-status textarea').val(''); | |
} | |
}); | |
}); | |
}); | |
*/ | |
//This code does a lot of stuff at the same time. | |
//It listens for page events, user events, network events, | |
//it does network IO, handles user input, parses the response, and does HTML templating. | |
/////////////SINGLE RESPONSIBILITY PRINCIPLE:: which is far easier to test, maintain, reuse and extend ///////// | |
//=>And we want to move as much as possible out of $(document).ready, so we can trigger the code ourselves | |
////////////Separating DOM and Ajax////////////////////////// | |
/* | |
function addStatus(){ | |
$.ajax({ | |
url: 'ajaxStatus.php', | |
type: 'POST', | |
dataType: 'json', | |
data: { text: $('#new-status textarea').val() }, //DOM | |
success: function(data) { | |
$('#statuses ul').append('<li>' + data.text + '</li>'); //DOM | |
$('#new-status textarea').val(''); //DOM | |
} | |
}); | |
} | |
$(document).ready(function() { | |
$('#new-status').submit(function(e) { //DOM | |
e.preventDefault(); | |
addStatus(); | |
}); | |
}); | |
*/ | |
////////////Separating DOM and Ajax////////////////////////// | |
/* | |
function addStatus(options) { | |
$.ajax({ | |
url: 'ajaxStatus.php', | |
type: 'POST', | |
dataType: 'json', | |
data: { text: options.text }, | |
success: options.success | |
}); | |
} | |
$(document).ready(function() { | |
$('#new-status form').submit(function(e) { //DOM | |
e.preventDefault(); | |
addStatus( | |
{ | |
text: $('#new-status textarea').val(), //DOM | |
success: function(data) { | |
$('#statuses ul').append('<li>' + data.text + '</li>'); //DOM | |
$('#new-status textarea').val(''); //DOM | |
} | |
} | |
); | |
}); | |
}); | |
*/ | |
////////////we want to wrap these statuses in an object and be able to write statuses.add instead of addStatus()////////////////////////// | |
//if it was module pattern !!! | |
/* | |
var statuses ={ | |
add : function(options){ | |
$.ajax({ | |
url: 'ajaxStatus.php', | |
type: 'POST', | |
dataType: 'json', | |
data: { text: options.text }, | |
success: options.success | |
}); | |
} | |
}; | |
*/ | |
/* | |
//constructor pattern with prototypes | |
var Statuses = function(){}; //Class | |
Statuses.prototype.add = function(options){ //method | |
$.ajax({ | |
url: 'ajaxStatus.php', | |
type: 'POST', | |
dataType: 'json', | |
data: { text: options.text }, | |
success: options.success | |
}); | |
} | |
////////////submit handler now has one dependency, the 'statuses' variable, and everything else within it is focused on the DOM//// | |
$(document).ready(function() { | |
var statuses = new Statuses(); //construct & initialize an object | |
$('#new-status').submit(function(e) { | |
e.preventDefault(); | |
statuses.add({ | |
text: $('#new-status textarea').val(), | |
success: function(data) { | |
$('#statuses ul').append('<li>' + data.text + '</li>'); | |
$('#new-status textarea').val(''); | |
} | |
}); | |
}); | |
}); | |
*/ | |
////////////Creating a view////////////////////////// | |
// Let's move the submit handler and everything inside it into its own class, NewStatusView: | |
//Now we only bootstrap our application when the DOM is loaded, and everything else is moved out of $(document).ready. | |
//The steps we have taken so far has given us two components which are easier to test and have more well-defined responsibilities. | |
/* | |
var Statuses = function(){}; | |
Statuses.prototype.add = function(options){ | |
$.ajax({ | |
url: 'ajaxStatus.php', | |
type: 'POST', | |
dataType: 'json', | |
data: { text: options.text }, | |
success: options.success | |
}); | |
} | |
var NewStatusView = function(options){ | |
var statuses = options.statuses; | |
$('#new-status').submit(function(e) { | |
e.preventDefault(); | |
statuses.add({ //!!! | |
text: $('#new-status textarea').val(), | |
success: function(data) { | |
$('#statuses ul').append('<li>' + data.text + '</li>'); | |
$('#new-status textarea').val(''); | |
} | |
}); | |
}); | |
}; | |
$(document).ready(function() { | |
var statuses = new Statuses(); | |
NewStatusView( | |
{statuses: statuses} | |
); | |
}); | |
*/ | |
//////////////////////////////////////splitting the submit handler in NewStatusView into its own addStatus method: ////////////////////// | |
/* | |
var Statuses = function(){}; | |
Statuses.prototype.add = function(options){ | |
$.ajax({ | |
url: 'ajaxStatus.php', | |
type: 'POST', | |
dataType: 'json', | |
data: { text: options.text }, | |
success: options.success | |
}); | |
} | |
var NewStatusView = function(options){ | |
this.statuses = options.statuses; //?????????????????? var statuses = options.statuses; | |
var add = $.proxy(this.addStatus, this); | |
$('#new-status form').submit(add); | |
}; | |
NewStatusView.prototype.addStatus = function(e){ | |
e.preventDefault(); | |
this.statuses.add({ //!!! | |
text: $('#new-status textarea').val(), | |
success: function(data) { | |
$('#statuses ul').append('<li>' + data.text + '</li>'); | |
$('#new-status textarea').val(''); | |
} | |
}); | |
}; | |
$(document).ready(function() { | |
var statuses = new Statuses(); | |
new NewStatusView( {statuses: statuses} ); | |
}); | |
*/ | |
///////////////////////////////////////Let's make the success callback call methods instead of working directly on the DOM, which makes the callback easier to read and work with: ///// | |
/* | |
var Statuses = function(){}; | |
Statuses.prototype.add = function(options){ | |
$.ajax({ | |
url: 'ajaxStatus.php', | |
type: 'POST', | |
dataType: 'json', | |
data: { text: options.text }, | |
success: options.success | |
}); | |
} | |
var NewStatusView = function(options){ | |
this.statuses = options.statuses; | |
var add = $.proxy(this.addStatus, this); | |
$('#new-status form').submit(add); | |
}; | |
NewStatusView.prototype.addStatus = function(e){ | |
e.preventDefault(); | |
var that = this; | |
this.statuses.add({ //!!! | |
text: $('#new-status textarea').val(), | |
success: function(data) { | |
that.appendStatus(data.text); | |
that.clearInput(); | |
} | |
}); | |
}; | |
NewStatusView.prototype.appendStatus = function(text){ | |
$('#statuses ul').append('<li>' + text + '</li>'); | |
} | |
NewStatusView.prototype.clearInput = function(){ | |
$('#new-status textarea').val(''); | |
} | |
$(document).ready(function() { | |
var statuses = new Statuses(); | |
new NewStatusView( {statuses: statuses} ); | |
}); | |
*/ | |
////////////////////Adding Backbone events//////////////////////////////////////////////////////////////////////////////////////////////////////////////// | |
// we let the success callback trigger an event instead of calling methods. | |
//by declaring which methods we want to call in the constructor when the event is triggered: | |
//Now we can declare in the constructor what we want to happen when a status is added, instead of addStatus being responsible for handling success. | |
//The only responsibility addStatus should have is backend communication, not updating the DOM. | |
// Events do not have to be declared before they are bound, and may take passed arguments. | |
/* | |
var events = _.clone(Backbone.Events); | |
var Statuses = function(){}; | |
Statuses.prototype.add = function(options){ | |
$.ajax({ | |
url: 'ajaxStatus.php', | |
type: 'POST', | |
dataType: 'json', | |
data: { text: options.text }, | |
success: options.success | |
}); | |
} | |
var NewStatusView = function(options){ | |
this.statuses = options.statuses; | |
events.on('status:add', this.appendStatus, this); | |
events.on('status:add', this.clearInput, this); | |
var add = $.proxy(this.addStatus, this); | |
$('#new-status form').submit(add); | |
}; | |
NewStatusView.prototype.addStatus = function(e){ | |
e.preventDefault(); | |
this.statuses.add({ //!!! | |
text: $('#new-status textarea').val(), | |
success: function(data) { | |
events.trigger('status:add', data.text); | |
} | |
}); | |
}; | |
NewStatusView.prototype.appendStatus = function(text){ | |
$('#statuses ul').append('<li>' + text + '</li>'); | |
} | |
NewStatusView.prototype.clearInput = function(){ | |
$('#new-status textarea').val(''); | |
} | |
$(document).ready(function() { | |
var statuses = new Statuses(); | |
new NewStatusView( {statuses: statuses} ); | |
}); | |
*/ | |
////////////As we no longer deal with the view in the success callback we can move the triggering of the event into the add method on Statuses///////////////////////// | |
/* | |
var events = _.clone(Backbone.Events); | |
var Statuses = function(){}; | |
Statuses.prototype.add = function(text){ | |
$.ajax({ | |
url: 'ajaxStatus.php', | |
type: 'POST', | |
dataType: 'json', | |
data: { text: text }, | |
success: function(data) { | |
events.trigger('status:add', data.text); | |
} | |
}); | |
} | |
var NewStatusView = function(options){ | |
this.statuses = options.statuses; | |
events.on('status:add', this.appendStatus, this); | |
events.on('status:add', this.clearInput, this); | |
var add = $.proxy(this.addStatus, this); | |
$('#new-status form').submit(add); | |
}; | |
NewStatusView.prototype.addStatus = function(e){ | |
e.preventDefault(); | |
this.statuses.add($('#new-status textarea').val()); | |
}; | |
NewStatusView.prototype.appendStatus = function(text){ | |
$('#statuses ul').append('<li>' + text + '</li>'); | |
} | |
NewStatusView.prototype.clearInput = function(){ | |
$('#new-status textarea').val(''); | |
} | |
$(document).ready(function() { | |
var statuses = new Statuses(); | |
new NewStatusView( {statuses: statuses} ); | |
}); | |
*/ | |
/////////////////A view's responsibilities ////////////////////////////////////////////////////////////////////////////////////////////////////////////// | |
//Separating responsibilities:: #statuses -> StatusesView || #new-status -> NewStatusView | |
//Let's pull a StatusesView out of #statuses, and let it be responsible for #statuses. | |
/* | |
var events = _.clone(Backbone.Events); | |
var Statuses = function(){}; | |
Statuses.prototype.add = function(text){ | |
$.ajax({ | |
url: 'ajaxStatus.php', | |
type: 'POST', | |
dataType: 'json', | |
data: { text: text }, | |
success: function(data) { | |
events.trigger('status:add', data.text); | |
} | |
}); | |
} | |
var NewStatusView = function(options){ | |
this.statuses = options.statuses; | |
events.on('status:add', this.clearInput, this); | |
var add = $.proxy(this.addStatus, this); | |
$('#new-status form').submit(add); | |
}; | |
NewStatusView.prototype.addStatus = function(e){ | |
e.preventDefault(); | |
this.statuses.add($('#new-status textarea').val()); | |
}; | |
NewStatusView.prototype.clearInput = function(){ | |
$('#new-status textarea').val(''); | |
} | |
var StatusesView = function(){ | |
events.on('status:add', this.appendStatus, this); | |
} | |
StatusesView.prototype.appendStatus = function(text){ | |
$('#statuses ul').append('<li>' + text + '</li>'); | |
} | |
$(document).ready(function() { | |
var statuses = new Statuses(); | |
new NewStatusView( {statuses: statuses} ); | |
new StatusesView(); | |
}); | |
*/ | |
/////////////////////////////As each view is now responsible for only one HTML element, we can specify them when instantiating the views://///////////////////////// | |
/* | |
var events = _.clone(Backbone.Events); | |
var Statuses = function(){}; | |
Statuses.prototype.add = function(text){ | |
$.ajax({ | |
url: 'ajaxStatus.php', | |
type: 'POST', | |
dataType: 'json', | |
data: { text: text }, | |
success: function(data) { | |
events.trigger('status:add', data.text); | |
} | |
}); | |
} | |
var NewStatusView = function(options){ | |
this.statuses = options.statuses; | |
this.el = $('#new-status'); | |
events.on('status:add', this.clearInput, this); | |
var add = $.proxy(this.addStatus, this); | |
this.el.find('form').submit(add); | |
}; | |
NewStatusView.prototype.addStatus = function(e){ | |
e.preventDefault(); | |
this.statuses.add(this.el.find('textarea').val()); | |
}; | |
NewStatusView.prototype.clearInput = function(){ | |
this.el.find('textarea').val(''); | |
} | |
var StatusesView = function(){ | |
this.el = $('#statuses'); | |
events.on('status:add', this.appendStatus, this); | |
} | |
StatusesView.prototype.appendStatus = function(text){ | |
this.el.find('ul').append('<li>' + text + '</li>'); | |
} | |
$(document).ready(function() { | |
var statuses = new Statuses(); | |
new NewStatusView( {statuses: statuses} ); | |
new StatusesView(); | |
}); | |
*/ | |
//////////////////////////////////////still difficult to test because they depend on having the HTML present////////////////////////////////// | |
///////////////////////////////To remedy this we can pass in its DOM dependencies when we instantiate a view. | |
//Now, this is easy to test! With this change we can use a jQuery trick to test our views. | |
//Instead of initiating our views by passing in for example $('#new-status'), we can pass in the necessary HTML wrapped in jQuery, e.g. $('<div><form>…</form></div>'). | |
//jQuery will then create the needed DOM elements on the fly. | |
/* | |
var events = _.clone(Backbone.Events); | |
var Statuses = function(){}; | |
Statuses.prototype.add = function(text){ | |
$.ajax({ | |
url: 'ajaxStatus.php', | |
type: 'POST', | |
dataType: 'json', | |
data: { text: text }, | |
success: function(data) { | |
events.trigger('status:add', data.text); | |
} | |
}); | |
} | |
var NewStatusView = function(options){ | |
this.statuses = options.statuses; | |
this.el = options.el; | |
events.on('status:add', this.clearInput, this); | |
var add = $.proxy(this.addStatus, this); | |
this.el.find('form').submit(add); | |
}; | |
NewStatusView.prototype.addStatus = function(e){ | |
e.preventDefault(); | |
this.statuses.add(this.el.find('textarea').val()); | |
}; | |
NewStatusView.prototype.clearInput = function(){ | |
this.el.find('textarea').val(''); | |
} | |
var StatusesView = function(options){ | |
this.el = options.el; | |
events.on('status:add', this.appendStatus, this); | |
} | |
StatusesView.prototype.appendStatus = function(text){ | |
this.el.find('ul').append('<li>' + text + '</li>'); | |
} | |
$(document).ready(function() { | |
var statuses = new Statuses(); | |
new NewStatusView( {el: $('#new-status') ,statuses: statuses} ); | |
new StatusesView({el: $('#statuses')}); | |
}); | |
*/ | |
///////////Our next step is introducing a helper to clean up our views a little bit. Instead of writing this.el.find we can create a simple helper so we can write this.$ instead/////////// | |
//With this little change it feels like we are saying, I want to use jQuery to look for something locally on this view instead of globally in the entire HTML. | |
/* | |
var events = _.clone(Backbone.Events); | |
var Statuses = function(){}; | |
Statuses.prototype.add = function(text){ | |
$.ajax({ | |
url: 'ajaxStatus.php', | |
type: 'POST', | |
dataType: 'json', | |
data: { text: text }, | |
success: function(data) { | |
events.trigger('status:add', data.text); | |
} | |
}); | |
} | |
var NewStatusView = function(options){ | |
this.statuses = options.statuses; | |
this.el = options.el; | |
events.on('status:add', this.clearInput, this); | |
var add = $.proxy(this.addStatus, this); | |
this.$('form').submit(add); | |
}; | |
NewStatusView.prototype.addStatus = function(e){ | |
e.preventDefault(); | |
this.statuses.add(this.$('textarea').val()); | |
}; | |
NewStatusView.prototype.clearInput = function(){ | |
this.$('textarea').val(''); | |
} | |
NewStatusView.prototype.$ = function(selector){ | |
return this.el.find(selector); | |
} | |
var StatusesView = function(options){ | |
this.el = options.el; | |
events.on('status:add', this.appendStatus, this); | |
} | |
StatusesView.prototype.appendStatus = function(text){ | |
this.$('ul').append('<li>' + text + '</li>'); | |
} | |
StatusesView.prototype.$ = function(selector){ | |
return this.el.find(selector); | |
} | |
$(document).ready(function() { | |
var statuses = new Statuses(); | |
new NewStatusView( {el: $('#new-status') ,statuses: statuses} ); | |
new StatusesView({el: $('#statuses')}); | |
}); | |
*/ | |
//However, adding this functionality for every view is a pain. That's one of the reasons to use Backbone.js views — reusing functionality across views. | |
//////////////////////////////Getting started with views in Backbone///////////////////////////////////////////////////////////////////////////////////// | |
/* | |
var events = _.clone(Backbone.Events); | |
var Statuses = function(){}; | |
Statuses.prototype.add = function(text){ | |
$.ajax({ | |
url: 'ajaxStatus.php', | |
type: 'POST', | |
dataType: 'json', | |
data: { text: text }, | |
success: function(data) { | |
events.trigger('status:add', data.text); | |
} | |
}); | |
} | |
var NewStatusView = Backbone.View.extend({ | |
initialize: function(options){ | |
this.statuses = options.statuses; | |
this.el = options.el; | |
events.on('status:add', this.clearInput, this); | |
var add = $.proxy(this.addStatus, this); | |
this.$('form').submit(add); | |
}, | |
addStatus: function(e){ | |
e.preventDefault(); | |
this.statuses.add(this.$('textarea').val()); | |
}, | |
clearInput: function(){ | |
this.$('textarea').val(''); | |
}, | |
$: function(selector){ | |
return this.el.find(selector); | |
} | |
}); | |
var StatusesView = function(options){ | |
this.el = options.el; | |
events.on('status:add', this.appendStatus, this); | |
} | |
StatusesView.prototype.appendStatus = function(text){ | |
this.$('ul').append('<li>' + text + '</li>'); | |
} | |
StatusesView.prototype.$ = function(selector){ | |
return this.el.find(selector); | |
} | |
$(document).ready(function() { | |
var statuses = new Statuses(); | |
new NewStatusView( {el: $('#new-status') ,statuses: statuses} ); | |
new StatusesView({el: $('#statuses')}); | |
}); | |
*/ | |
///////Now that we use Backbone.js views we can remove the this.$ helper, as it already exists in Backbone. | |
////////////We also no longer need to set this.el ourselves, as Backbone.js does it automatically when a view is instantiated with an HTML element. | |
/* | |
var events = _.clone(Backbone.Events); | |
var Statuses = function(){}; | |
Statuses.prototype.add = function(text){ | |
$.ajax({ | |
url: 'ajaxStatus.php', | |
type: 'POST', | |
dataType: 'json', | |
data: { text: text }, | |
success: function(data) { | |
events.trigger('status:add', data.text); | |
} | |
}); | |
} | |
var NewStatusView = Backbone.View.extend({ | |
initialize: function(options){ | |
this.statuses = options.statuses; | |
events.on('status:add', this.clearInput, this); | |
var add = $.proxy(this.addStatus, this); | |
this.$('form').submit(add); | |
}, | |
addStatus: function(e){ | |
e.preventDefault(); | |
this.statuses.add(this.$('textarea').val()); | |
}, | |
clearInput: function(){ | |
this.$('textarea').val(''); | |
} | |
}); | |
var StatusesView = Backbone.View.extend({ | |
initialize: function(options){ | |
events.on('status:add', this.appendStatus, this); | |
}, | |
appendStatus: function(text){ | |
this.$('ul').append('<li>' + text + '</li>'); | |
} | |
}); | |
$(document).ready(function() { | |
var statuses = new Statuses(); | |
new NewStatusView( {el: $('#new-status') ,statuses: statuses} ); | |
new StatusesView({el: $('#statuses')}); | |
}); | |
*/ | |
/////////////////////////////////Let's use a model: responsible for the network traffic///////////////////////////////////////////////////////////////////////////////// | |
/// Backbone nicely abstracts Ajax, we don't need to specify "type", "dataType" and "data" anymore | |
//we only need to specify the URL and call "save" on the model. | |
//The "save" method accepts the data we want to save as the first parameter, and options, such as the success callback, as the second parameter. | |
/* | |
var events = _.clone(Backbone.Events); | |
var Status = Backbone.Model.extend({ | |
url: 'ajaxStatus.php' | |
}); | |
var Statuses = function(){}; | |
Statuses.prototype.add = function(text){ | |
var status = new Status(); | |
status.save({text: text}, { | |
success: function(model, data){ // model ???????? | |
events.trigger('status:add', data.text); | |
} | |
}); | |
} | |
var NewStatusView = Backbone.View.extend({ | |
initialize: function(options){ | |
this.statuses = options.statuses; | |
events.on('status:add', this.clearInput, this); | |
var add = $.proxy(this.addStatus, this); | |
this.$('form').submit(add); | |
}, | |
addStatus: function(e){ | |
e.preventDefault(); | |
this.statuses.add(this.$('textarea').val()); | |
}, | |
clearInput: function(){ | |
this.$('textarea').val(''); | |
} | |
}); | |
var StatusesView = Backbone.View.extend({ | |
initialize: function(options){ | |
events.on('status:add', this.appendStatus, this); | |
}, | |
appendStatus: function(text){ | |
this.$('ul').append('<li>' + text + '</li>'); | |
} | |
}); | |
$(document).ready(function() { | |
var statuses = new Statuses(); | |
new NewStatusView( {el: $('#new-status') ,statuses: statuses} ); | |
new StatusesView({el: $('#statuses')}); | |
}); | |
*/ | |
///Handling several models: COLLECTIONS ///////////////////////////////////// | |
// we have introduced models, we need a concept for a list of models, such as the list of statuses in our application: Collections | |
//really cool thing about collections is that they have scoped events. | |
//Basically, this just means that we can bind and trigger events directly on a collection instead of using our events variable — | |
//our events will live on statuses instead of events. | |
// As we now start firing events directly on statuses there's no need for "status" in the event name, so we rename it from "status:add" to "add". | |
/* | |
var Status = Backbone.Model.extend({ | |
url: 'ajaxStatus.php' | |
}); | |
var Statuses = Backbone.Collection.extend({ | |
add: function(text){ | |
var status = new Status(); | |
var that = this; | |
status.save({text: text}, { | |
success: function(model, data){ // model ???????? | |
that.trigger('add', data.text); // !!! "add" method --> triggers "add" event ==> triggers view Methods for DOM manipulation | |
//console.log(model); | |
//console.log(model.attributes); // same => console.log(data); | |
} | |
}); | |
} | |
}); | |
var NewStatusView = Backbone.View.extend({ | |
initialize: function(options){ | |
this.statuses = options.statuses; | |
this.statuses.on('add', this.clearInput, this); | |
var add = $.proxy(this.addStatus, this); | |
this.$('form').submit(add); | |
}, | |
addStatus: function(e){ | |
e.preventDefault(); | |
this.statuses.add(this.$('textarea').val()); | |
}, | |
clearInput: function(){ | |
this.$('textarea').val(''); | |
} | |
}); | |
var StatusesView = Backbone.View.extend({ | |
initialize: function(options){ | |
this.statuses = options.statuses; | |
this.statuses.on('add', this.appendStatus, this); | |
}, | |
appendStatus: function(text){ | |
this.$('ul').append('<li>' + text + '</li>'); | |
} | |
}); | |
$(document).ready(function() { | |
var statuses = new Statuses(); | |
new NewStatusView( {el: $('#new-status') ,statuses: statuses} ); | |
new StatusesView({el: $('#statuses'),statuses: statuses}); | |
}); | |
*/ | |
////////////////////////////// As with el earlier, Backbone.js automatically sets "this.collection" when collection is passed. Therefore we rename statuses to collection in our view:/// | |
/* | |
var Status = Backbone.Model.extend({ | |
url: 'ajaxStatus.php' | |
}); | |
var Statuses = Backbone.Collection.extend({ | |
add: function(text){ | |
var status = new Status(); ///creates a new model instance | |
var that = this; | |
status.save({text: text}, { //saves it to the server | |
success: function(model, data){ //adds it to the collection | |
that.trigger('add', data.text); //"add" event to be triggered on the collection, | |
} | |
}); | |
} | |
}); | |
var NewStatusView = Backbone.View.extend({ | |
initialize: function(){ | |
this.collection.on('add', this.clearInput, this); | |
var add = $.proxy(this.addStatus, this); | |
this.$('form').submit(add); | |
}, | |
addStatus: function(e){ | |
e.preventDefault(); | |
this.collection.add(this.$('textarea').val()); | |
}, | |
clearInput: function(){ | |
this.$('textarea').val(''); | |
} | |
}); | |
var StatusesView = Backbone.View.extend({ | |
initialize: function(){ | |
this.collection.on('add', this.appendStatus, this); | |
}, | |
appendStatus: function(text){ | |
this.$('ul').append('<li>' + text + '</li>'); | |
} | |
}); | |
$(document).ready(function() { | |
var statuses = new Statuses(); | |
new NewStatusView( {el: $('#new-status') ,collection: statuses} ); | |
new StatusesView({el: $('#statuses'),collection: statuses}); | |
}); | |
*/ | |
//////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// | |
/////////////////We can simplify this even more by using Backbone's create method. It creates a new model instance, adds it to the collection and saves it to the server./////////// | |
//1-When creating the status we need to pass in an options hash with the attributes we want to save, instead of only passing the text. | |
//2-The built in "create" also triggers an "add" event, but rather than passing only the text, as we have done so far, it passes the newly created model. | |
//We can get the text from the model by calling ' model.get("text") ' | |
// this.$('ul').append('<li>' + text ==> status.get("text") + '</li>'); | |
// pass wait:true to the .create() if you'd like to wait for the server before adding the new model to the collection. | |
/* | |
var Status = Backbone.Model.extend({ | |
url: 'ajaxStatus.php' | |
}); | |
var Statuses = Backbone.Collection.extend({ | |
model: Status //In order for collection.create() to work, you should set the model property of the collection | |
}); | |
var NewStatusView = Backbone.View.extend({ | |
initialize: function(){ | |
this.collection.on('add', this.clearInput, this); | |
var add = $.proxy(this.addStatus, this); | |
this.$('form').submit(add); | |
}, | |
addStatus: function(e){ | |
e.preventDefault(); | |
this.collection.create({text: this.$('textarea').val()}, {wait:true}); // !!!! passed wait:true this.collection.create({text: this.$('textarea').val()}); | |
//COLLECTION.create()=> 1-creates a new model instance 2-saves it to the server 3-adds it to the collection | |
// 4- Creating a model will cause an immediate "add" event to be triggered on the collection, as well as a "sync" event, once the model has been successfully created on the server | |
// 5- Pass {wait: true} if you'd like to wait for the server before adding the new model to the collection. | |
}, | |
clearInput: function(){ | |
this.$('textarea').val(''); | |
} | |
}); | |
var StatusesView = Backbone.View.extend({ | |
initialize: function(){ | |
this.collection.on('add', this.appendStatus, this); | |
}, | |
appendStatus: function(status){ //==> this could be left as: function(text) and text.get("text") ,, just naming | |
console.log(status); | |
this.$('ul').append('<li>' + status.get("text") + '</li>'); | |
} | |
}); | |
$(document).ready(function() { | |
var statuses = new Statuses(); | |
new NewStatusView( {el: $('#new-status') ,collection: statuses} ); | |
new StatusesView({el: $('#statuses'),collection: statuses}); | |
}); | |
*/ | |
///////////////////////////////////////////////////Evented Views//////////////////////////////////////////////////////////////////// | |
//Now, let's get rid of that nasty $.proxy stuff. We can do this by letting Backbone.js delegate our events by specifying them in an "events" hash in the view. | |
//This hash is on the format {"event selector": "callback"} ===> in a View => events: { "submit form" : "addStatus" } | |
/* | |
var Status = Backbone.Model.extend({ | |
url: 'ajaxStatus.php' | |
}); | |
var Statuses = Backbone.Collection.extend({ | |
model: Status | |
}); | |
var NewStatusView = Backbone.View.extend({ | |
events: { | |
'submit form' : 'addStatus' | |
}, | |
initialize: function(){ | |
this.collection.on('add', this.clearInput, this); | |
//var add = $.proxy(this.addStatus, this); | |
//this.$('form').submit(add); | |
}, | |
addStatus: function(e){ | |
e.preventDefault(); | |
this.collection.create({text: this.$('textarea').val()}, {wait:true}); // !!!! passed wait:true this.collection.create({text: this.$('textarea').val()}); | |
}, | |
clearInput: function(){ | |
this.$('textarea').val(''); | |
} | |
}); | |
var StatusesView = Backbone.View.extend({ | |
initialize: function(){ | |
this.collection.on('add', this.appendStatus, this); | |
}, | |
appendStatus: function(status){ | |
console.log(status); | |
this.$('ul').append('<li>' + status.get("text") + '</li>'); | |
} | |
}); | |
$(document).ready(function() { | |
var statuses = new Statuses(); | |
new NewStatusView( {el: $('#new-status') ,collection: statuses} ); | |
new StatusesView({el: $('#statuses'),collection: statuses}); | |
}); | |
*/ | |
//////////////////////////Escape it! prevent XSS-exploits. Instead of using model.get('text') let's use the built-in escape handling and write model.escape('text') //////////// | |
///If you're using Handlebars, Mustache or similar templating engines, you might get this functionality out of the box. | |
var Status = Backbone.Model.extend({ | |
url: 'ajaxStatus.php' | |
}); | |
var Statuses = Backbone.Collection.extend({ | |
model: Status | |
}); | |
var NewStatusView = Backbone.View.extend({ | |
events: { | |
'submit form' : 'addStatus' | |
}, | |
initialize: function(){ | |
this.collection.on('add', this.clearInput, this); | |
}, | |
addStatus: function(e){ | |
e.preventDefault(); | |
this.collection.create({text: this.$('textarea').val()}, {wait:true}); // !!!! passed wait:true this.collection.create({text: this.$('textarea').val()}); | |
}, | |
clearInput: function(){ | |
this.$('textarea').val(''); | |
} | |
}); | |
var StatusesView = Backbone.View.extend({ | |
initialize: function(){ | |
this.collection.on('add', this.appendStatus, this); | |
}, | |
appendStatus: function(status){ | |
console.log(status); | |
this.$('ul').append('<li>' + status.escape("text") + '</li>'); | |
} | |
}); | |
$(document).ready(function() { | |
var statuses = new Statuses(); | |
new NewStatusView( {el: $('#new-status') ,collection: statuses} ); | |
new StatusesView({el: $('#statuses'),collection: statuses}); | |
}); | |
</script> | |
</body> | |
</html> |
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
<!DOCTYPE html> | |
<html> | |
<head> | |
<meta charset='UTF-8'> | |
<title>HTML Document</title> | |
<link href="http://fonts.googleapis.com/css?family=Abel" rel="stylesheet" type="text/css"> | |
<style type="text/css"> | |
body { padding: 0; margin: 0; background-color: #fff; } | |
h2 { font-family: Abel, sans-serif; margin: 0; padding: 0 0 5px 0;} | |
input { background-color: #ddd; border: 0; } | |
input:active { background-color: #bbb; } | |
#new-status { margin: 20px; padding: 20px; background-color: #67A9C3; } | |
#statuses { margin: 20px; padding: 20px; background-color: #92B456; } | |
</style> | |
<script src="//ajax.googleapis.com/ajax/libs/jquery/1.8.1/jquery.min.js"></script> | |
<script src="underscore.js"></script> | |
<script src="backbone.js"></script> | |
</head> | |
<body> | |
<div id="new-status"> | |
<h2>New monolog</h2> | |
<form action=""> | |
<textarea></textarea><br> | |
<input type="submit" value="Post"/> | |
</form> | |
</div> | |
<div id="statuses"> | |
<h2>Monologs</h2> | |
<ul></ul> | |
</div> | |
<script > | |
$(document).ready(function() { //wait for DOM to load (listen page event) | |
$('#new-status form').submit(function(e) { //set a submit listener (listen user event) | |
e.preventDefault(); | |
var text = $('#new-status textarea').val(); | |
//console.log(text); | |
var data = {}; | |
data.text = text; | |
//console.log(data.text); | |
data = JSON.stringify(data); | |
//console.log(data); | |
$.ajax({ //send input to the server | |
url: 'ajaxStatus.php', | |
type: 'POST', | |
contentType: 'json', /////////????? doesnt send in json format | |
dataType: 'json', | |
data: data, | |
success: function(data) { //listen network event | |
console.log(data); | |
//parse the response | |
$('#statuses ul').append('<li>' + data.text + '</li>'); // HTML templating | |
$('#new-status textarea').val(''); | |
} | |
}); | |
}); | |
}); | |
//This code does a lot of stuff at the same time. | |
//It listens for page events, user events, network events, | |
//it does network IO, handles user input, parses the response, and does HTML templating. | |
////////////////////////////////////// | |
/* | |
var ItemView = Backbone.View.extend({ | |
tagName: 'li' | |
}); | |
var BodyView = Backbone.View.extend({ | |
el: 'body' | |
}); | |
var | |
SomethingView = Backbone.View.extend({ | |
id: 'container' | |
}); | |
var item = new ItemView(); | |
var item2 = new BodyView(); | |
var item3 = new SomethingView(); | |
//item3.setElement(item); | |
console.log(item); | |
console.log(item.el); | |
console.log(item.tagName); | |
console.log(item2.el); | |
console.log(item3.el); | |
console.log(item3.$el); | |
item3.$el.html("some text"); | |
console.log(item3.$el); | |
item3.$el.appendTo('#statuses ul'); | |
*/ | |
</script> | |
</body> | |
</html> |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment