TASK 3
now your code should have repeat code
each time you want to add something new to the page, you'll probalily copy this code and make some minor change:
function renderGist(){
getGists().then(function(body){
$('.container .article').html(nunjucks.render("src/templates/gistlist.html",{gists:body}));
}).then(bindEvent);
}
Once you have to copy and paste your code, that means you need refactory
look at the code and you'll see the common things: 1. get Data from backend 2. use the data to render template 3. bind event to the element after the template rendered.
So, TASK 3 would be:
extract the View out of the common code
Check Points
- remove repeat code and replace them with View
- View can be extend -- inheritance
- View should be easy to use like backbone
Hint:
this will explain how to implement simple javascript inheritance using underscore
function Mammal(name){
this.name=name;
this.offspring=[];
}
Mammal.prototype.toString=function(){
return '[Mammal "'+this.name+'"]';
}
Mammal.extend = function(props){
var parent = this,child;
child = function(){
parent.apply(this, arguments)
}
var FixConstructor = function(){
this.constructor = child;
};
FixConstructor.prototype = parent.prototype
child.prototype = new FixConstructor();
_.extend(child, parent);
_.extend(child.prototype,props);
return child;
}
var Cat = Mammal.extend({type:"Cat"})
var cat = new Cat("meow")
Walkthrough
prototype
+----------------+ prototype+-----------------+
| Function +----------+ function |
+-------+--------+ +-----------------+
|
|Mammal instanceof Function === true
|.constructor
+-------+--------+ prototype+----------------+
| Mammal +----------+ empty Object {}
+----------------+ +----------------+
.. .. . . . . .Mammal.prototype.toString=function() .............
+------------------+ +----------------------+
| Mammal |.prototype | {}.toString |
+------------------+ +-----------+----------+
| .extend | ^
+------------------+ |
.......^.......var mammal= new Mammal("dog") .|................... | |toString | Object.getPrototypeOf +-----------+-----------+ +---------------------------+ mammal | .constructor +-----------------------+
constructor
as you can see here, Mammal.constructor == Function
mammal.constructor == Mammal
so function Mammal()
just like create new instance of Function
Function
- Function
new Function (arg1, arg2, ... argN, functionBody)
- function statment
function name([param[, param[, ... param]]]) {
statements
}
- function operater/expression
function [name]([param] [, param] [..., param]) {
statements
}
- Function constructor vs. function declaration vs. function expression
Function constructor
var multiply = new Function("x", "y", "return x * y;");
function declaration
function multiply(x, y) {
return x * y;
}
function expression
var multiply = function(x, y) {
return x * y;
};
named function expression
var multiply = function func_name(x, y) {
return x * y;
};
implement the inheritance of View,just like the mammal:
View.extend = function(props){
var parent = this,child;
child = function(){
parent.apply(this, arguments);
};
child.parent=parent;
var FixConstructor = function(){
this.constructor = child;
};
FixConstructor.prototype = parent.prototype;
child.prototype = new FixConstructor();
_.extend(child, parent);
_.extend(child.prototype,props);
return child;
};
- the mighty basic View
_.extend(View.prototype, {
el:$("body"),
templateEngine: nunjucks,
template:"",
data:"",
events:"click body:",
initialize:function(){
},
getData:function(options){
if (!this.data) return Q();
var methodAndUrl = this.data.split('@');
return Q($.ajax(_.extend({
url:methodAndUrl[1],
method:methodAndUrl[0]
},options)));
},
render:function(){
var self = this;
return this.getData(this.dataOptions).then(function(data){
self.el.html(self.templateEngine.render(self.template, {data:data}));
}).then(self.bindEvent.bind(self));
},
bindEvent:function(){
var self = this;
var events = _.result(this, 'events');
if (!events) return this;
_.each(_(events).keys(),function(key){
var match = key.match(delegateEventSplitter);
var eventName = match[1], selector = match[2];
if (selector==''){
self.el.on(eventName, _.bind(self[events[key]],self));
} else{
self.el.find(selector).on(eventName, _.bind(self[events[key]],self));
}
});
}
});