Download BackBone.js File
BackBone.js GitHub Repository
https://github.com/jashkenas/backbone
Upload Static Resource
- backbone.js
- jquery.js
- underscore.js
BackBoneJsTaskApp.page
<apex:page title="Backbone.js" showHeader="true" sidebar="false">
<apex:include pageName="BackBoneJsTaskAppCss" />
<div id="vf-page">
<h1>Tasks</h1>
<form id="addTask">
<input type="text" id="title" />
<input type="submit" value="add" />
<span id="error"></span>
</form>
<div id="tasks"></div>
<p>Tasks Count: <span id='count'></span></p>
<script type="text/template" id="task-template">
<input type="checkbox" class="toggle" <%= completed ? 'checked': '' %>></input>
<span class="<%= completed ? 'completed' : '' %>">
<%- title %>
<span class="delete">[x]</span>
</span>
</script>
</div>
<apex:includeScript value="{!URLFOR($Resource.BackBoneJS, 'js/underscore.js')}" />
<apex:includeScript value="{!URLFOR($Resource.BackBoneJS, 'js/jquery.js')}" />
<apex:includeScript value="{!URLFOR($Resource.BackBoneJS, 'js/backbone.js')}" />
<apex:include pageName="BackBoneJsTaskAppScript"/>
</apex:page>
BackBoneJsTaskAppScript.page
<apex:page >
<script type="text/javascript">
(function() {
// Model
var Task = Backbone.Model.extend({
defaults: {
title: 'do something',
completed: false
},
validate: function(attrs) {
if ( _.isEmpty(attrs.title)) {
return 'title must not be empty';
}
},
initialize: function() {
this.on('invalid', function(model, error) {
$('#error').html(error);
})
}
});
var Tasks = Backbone.Collection.extend({ model: Task});
// View
var TaskView = Backbone.View.extend({
tagName: 'li',
initialize: function() {
this.model.on('destroy', this.remove, this);
this.model.on('change', this.render, this);
},
events: {
'click .delete': 'destroy',
'click .toggle': 'toggle'
},
toggle: function() {
this.model.set('completed', !this.model.get('completed'));
},
destroy: function() {
if (confirm('are you sure?')) {
this.model.destroy();
}
},
remove: function() {
this.$el.remove();
},
template: _.template($('#task-template').html()),
render: function() {
var template = this.template(this.model.toJSON());
this.$el.html(template);
return this;
}
});
var TasksView = Backbone.View.extend({
tagName: 'ul',
initialize: function() {
this.collection.on('add', this.addNew, this);
this.collection.on('change', this.updateCount, this);
this.collection.on('destroy', this.updateCount, this);
},
addNew: function(task) {
var taskView = new TaskView({model: task});
this.$el.append(taskView.render().el);
$('#title').val('').focus();
this.updateCount();
},
updateCount: function() {
var uncompletedTasks = this.collection.filter(function(task) {
return !task.get('completed');
});
$('#count').html(uncompletedTasks.length);
},
render: function() {
this.collection.each(function(task) {
var taskView = new TaskView({model: task});
this.$el.append(taskView.render().el);
}, this);
this.updateCount();
return this;
}
});
var AddTaskView = Backbone.View.extend({
el : '#addTask',
events: {
'submit': 'submit'
},
submit: function(e) {
e.preventDefault();
//var task = new Task({title: $('#title').val()});
var task = new Task();
if (task.set({title: $('#title').val()}, {validate: true})) {
this.collection.add(task);
$('#error').empty();
}
}
});
var tasks = new Tasks([
{
title: 'task1',
completed: true
},
{
title: 'task2'
},
{
title: 'task3'
}
]);
var tasksView = new TasksView({collection: tasks});
var addTaskView = new AddTaskView({collection: tasks});
$('#tasks').html(tasksView.render().el);
})();
</script>
</apex:page>
BackBoneJsTaskAppCss.page
<apex:page >
<style type="text/css">
#vf-page * {
font-family: 'メイリオ', sans-serif;
font-size: 18px;
}
#vf-page input[type=text] {
font-size: 14px;
padding: 5px;
width: 200px;
}
#vf-page ul li {
list-style-type: none;
}
#vf-page .completed {
text-decoration: line-through;
color: gray;
}
#error {
color: red;
}
</style>
</apex:page>