forked from knockout/knockout
-
Notifications
You must be signed in to change notification settings - Fork 0
Scott's method
sv01a edited this page Apr 27, 2012
·
2 revisions
This code comes from Scott's app: commoncurriculum.com. Much of it has been simplified to make it easy to get the big picture.
app/ -models/ -bindings/ application.js router.js fetchers.js
var App = {
VMs : {
,unit : ko.observable()
,course : ko.observable()
,user : ko.observable()
}
,template : ko.observable()
,fetchers : {}
,trackers : {}
,init: function() {
new App.Router();
Backbone.history.start();
addTrackers(App.VMs.trackers)
ko.applyBindings(App.VMs)
}
}
Download the latest backbone.js and include the JS in your app.
App.Router = Backbone.Router.extend({
routes : {
"" : "home"
,"!/:username" : "show_user"
,"!/:username/:course_slug": "show_course"
,"!/:username/:course_slug/:unit_id": "show_unit"
// MORE ROUTES....
}
,home : function(){
Backbone.history.navigate("#!/" + cu.username, true) //cu is a javascript variable set on the server side when the page is served. It stands for current_user
}
,show_user : function(username){
App.fetchers.user(username, function(user){
App.VMs.user(user)
App.template('show_user')
}
}
,show_course : function(username, course_slug){
App.fetchers.course(username, course_slug, function(course){
App.VMs.course(course)
App.template('show_course')
})
}
,show_unit = function(){ .... }
}
App.fetchers = {
course : function(username, course_slug, cb){
amplify.request('course#read',
{ username: username, course_slug : course_slug},
function(data){
if( typeof cb !== 'undefined') {cb(new Course(data))}
}
)
}
,user : function(username, cb){
// ....
}
,unit : function(data, cb){
// ....
}
}
amplify.request.define('user#read', "ajax", {
url : "api/v1/users/{username}"
,dataType: "json"
,type: "GET"
})
amplify.request.define('user#update', "ajax", {
url : "api/v1/users/{username}"
,dataType: "json"
,type: "PUT"
})
// MORE AMPLIFY.JS REQUESTS HERE....
var Unit = function(data){
var _this = this
// Here are a couple of the instance methods I use instance methods in the model
this.older_sibling = function(){
this.siblings()[this.position]
}
this.has_younger_sibling = function(){
return this.position() == 1 ? false : true
}
this.younger_sibling = function(){
return this.siblings()[this.position() -1]
}
// I LOVE the mappings plugin. I put the mappings in my model.
// The first mapping allows me to use recursion to create nested models!
var mappings = {
'units' : {
key: function(item) {
return ko.utils.unwrapObservable(item.id);
}
,create: function(options){
return new Unit(options.data)
}
}
,'documents' : {
create : function(options){
return new Document(options.data)
}
}
}
// this makes the mappings work
ko.mapping.fromJS(data, mappings, this)
// I also put my persistence methods in my model.
this.save = function(course){
amplify.request({
resourceId: 'unit#update'
,data: data
,success: function(){show_save()}
,error: function(){lost_connection()}
})
}
this.destroy = function(course, context){
var _this = this
if (confirm("Are you sure you want to delete this?")){
amplify.request({
resourceId: 'unit#delete'
,data: { username : course().username()
,course_slug : course().slug()
,id : this.id()
}
,success: function(){
context.remove(_this);
show_save();
}
,error: function(){lost_connection()}
})
}
}
// I let knockout track all the changes to my model and use the dirty flag that Ryan made
// http://www.knockmeout.net/2011/05/creating-smart-dirty-flag-in-knockoutjs.html
this.dirtyFlag = new ko.dirtyFlag(_this, false)
// I track the changes to my nested models so that when they change, they're automatically saved.
this.dirtyUnits = ko.dependentObservable(function() {
return ko.utils.arrayFilter(this.units(), function(unit) {
if (typeof unit.dirtyFlag !== 'undefined') {
return unit.dirtyFlag.isDirty();
}
});
}, this);
this.dirtyDocuments = ko.dependentObservable(function() {
return ko.utils.arrayFilter(this.documents(), function(document) {
if (typeof document.dirtyFlag !== 'undefined') {
return document.dirtyFlag.isDirty();
}
});
}, this);
this.tracked_units = ko.dependentObservable(function(){
_.each(this.dirtyUnits(), function(unit){
unit.save(App.VMs.course)
unit.dirtyFlag.reset()
})
}, this)
this.tracked_documents = ko.dependentObservable(function(){
_.each(this.dirtyDocuments(), function(doc){
doc.save(App.VMs.course())
doc.dirtyFlag.reset()
})
}, this)
}
// I like to control what I serialize back to the server, so I change the toJSON. Read more here:
// http://www.knockmeout.net/2011/04/controlling-how-object-is-converted-to.html
Unit.prototype.toJSON = function(){
var copy = ko.mapping.toJS(this);
copy.doc_ids = _.map(copy.documents, function(document){return document.id});
copy.content_ids = _.map(copy.contents, function(content){return content.id});
copy.children_ids = _.map(copy.units, function(unit){return unit.id});
return {
id : copy.id
,title : copy.title
,subtitle : copy.subtitle
,text : copy.text
,content_ids : copy.content_ids
,children_ids : copy.children_ids
,nested_children :copy.nested_children
,doc_ids : copy.doc_ids
}
}