backbone.js and jquery mobile build a language trainer
March 11th 2011To learn some more about backbone.js and jquery mobile I decided to build a little language trainer. I’m currently studying German and have lots of trouble learning the genders of all the words.
After a number of iterations I finally got the hang of seperating the model and view code out and linking them all with events.
The basic premise of the app is to show you a word and you have to click either der, die or _das and it will either tell you you are wrong and let you try again or if you are right hit the server and ask for a new word and then present it to you.
I originally wrote this with just jquery mobile ui and let the server do all the rendering but on my HTC Desire the latency was intollerable for such an app and I decided to do most of it in javascript.
The code for the application is below
$('#mainPage').live('pagecreate',function(event){
// Source of words. Generates JSON data of
// the form
//
// { word: "Mann", article: "der" }
var Word = Backbone.Model.extend({
initialize: function() {
this.fetch();
this.set({message: ''});
}
,url: '/words/new.json'
,setAnswer: function (article){
txt = article + " " + this.get('word');
if (article == this.get('article')){
this.set({message: txt + " is correct"});
this.fetch();
}else{
this.set({message: txt + " is incorrect"});
}
}
});
var WordView = Backbone.View.extend({
word: new Word()
, initialize: function() {
this.bindModel();
}
// ---------------------
// Model Event Handling
// ---------------------
, bindModel: function(){
_.bindAll(this, "renderMessage", "renderWord");
this.word.bind('change:message', this.renderMessage);
this.word.bind('change:word', this.renderWord);
}
, renderWord: function(){
$("#word h1").html(this.word.get('word'));
}
, renderMessage: function(){
$("#messages").html(this.word.get('message'));
}
// ------------------
// UI Event Handling
// ------------------
, events: { "click .der" : "handleDer" ,
"click .die" : "handleDie" ,
"click .das" : "handleDas" ,
}
, handleDer: function(data) {
this.word.setAnswer('der');
}
, handleDie: function(data) {
this.word.setAnswer('die');
}
, handleDas: function(data) {
this.word.setAnswer('das');
}
});
// Attach the view to an element
var view = new WordView({el: $("#derdiedas")});
})
the view is generated by the following haml layout
!!! 5
%html
%head
%title Oh My Der Die Das
= javascript_include_tag :defaults
%link{:href => "http://code.jquery.com/mobile/1.0a3/jquery.mobile-1.0a3.min.css", :rel => "stylesheet"}/
%script{:src => "http://code.jquery.com/mobile/1.0a3/jquery.mobile-1.0a3.min.js"}
%script{:src =>"http://documentcloud.github.com/underscore/underscore-min.js"}
%script{:src =>"http://documentcloud.github.com/backbone/backbone-min.js"}
= javascript_include_tag 'words'
= csrf_meta_tag
%body
%div{:id => "mainPage", "data-role" => "page"}
= content_tag :div, "", :id => "messages", :class => "ui-body ui-body-e"
= yield
and view
%div{:id=>"word", :data => {:role => "header", :backbtn=>"false" }}
%h1=@word[:word]
%div{ :data => {:role => "content" }}
%ul{:id=>"derdiedas", :data => { :role=> "listview" }}
%li
%a.der(data-role="button" rel="external") der
%li
%a.die(data-role="button" rel="external") die
%li
%a.das(data-role="button" rel="external") das
and I have a controller at /words/new.json that generates data like
// { word: "Mann", article: "der" }
There is currently a working app at ohmyderdiedas. It is obviously best viewed on a modern smart phone though it does work in a desktop browser.