Getting data from the server is by default an asynchronous call, so why wouldn't you use a command instead of request/response and listen to the model events? I think it would be easier.
On this topic, I would create a channel that will provide,
- the command to fetch data
- the model or the collection instances the channel applies on.
and then the controller just has to subscribe to the channel to get the data and will listen to the collection instance events (sync error change, whatever basic backbone events on model/collection you want)
/* Constants: Simulation of API data. */
Constants = {};
Constants.jsonLanguages = [
{Name: "English", Code: "en", isEditable:true},
{Name: "French", Code: "fr", isEditable:false},
{Name: "German", Code: "de", isEditable:true},
{Name: "Spanish", Code: "es", isEditable:false}
];
Constants.jsonBook = {
Title: "Dune",
AuthorName: "Frank Herbert",
LanguageCode: "en",
ISBN: "978-1-4493-9268-0"
};
/* ----------------------------------------------------------------------------- */
/* Models */
// Language/Models.js
var models = {};
models.Language = Backbone.Model.extend({
defaults: {
Name: "English",
Code: "en"
},
idAttribute:"Code",
url: "/echo/json/"
});
models.LanguageCollection = Backbone.Collection.extend({
model: models.Language,
url: "/echo/json/"
});
// Book/Models.js
models.Book = Backbone.Model.extend({
defaults: {
Title: "",
AuthorName: "",
Language: null
},
url: "/echo/json/",
idAttribute: "ISBN"
});
/* ----------------------------------------------------------------------------- */
/* Channels: Manage data between server and client.
- dependencies : wreqr, related models, related routes */
// Languages/Channel.js
var LanguageChannel = {};
LanguageChannel.data = {};
LanguageChannel.data.workingLanguage = new models.Language();
LanguageChannel.data.languages = new models.LanguageCollection();
LanguageChannel.channel = Backbone.Wreqr.radio.channel("Languages");
LanguageChannel.channel.commands.setHandler("getLanguages", function() {
// here you typically fetch the data using backbone collection and backbone router
window.console && console.log("LanguageChannel.channel.command.getLanguages()");
LanguageChannel.data.languages.reset(Constants.jsonLanguages);
LanguageChannel.data.languages.trigger("sync");
});
// Books/Channel.js
var BookChannel = {};
BookChannel.data = {};
BookChannel.data.book = new models.Book();
BookChannel.channel = Backbone.Wreqr.radio.channel("Books");
BookChannel.channel.commands.setHandler("getBook", function(id){
// here you typically fetch the data using backbone model & backbone router
window.console && console.log("BookChannel.channel.commands.getBook(" + id +")");
BookChannel.data.book.set(Constants.jsonBook, {reset:true});
BookChannel.data.book.trigger("sync");
});
/* ----------------------------------------------------------------------------- */
/* Views: Manage template and view events. */
// Book/Views.js
BookAttributesView = Marionette.ItemView.extend({
el: "#BookAttributesBox",
template: "#BookAttributesTemplate",
bindings:
{
"#Title": "Title",
"#AuthorName": "AuthorName",
"#LanguageCode": {
observe: "LanguageCode",
selectOptions: {
collection: LanguageChannel.data.languages,
labelPath: "Name",
valuePath: "Code"
},
update: function($el, val, model, options) {
window.console && console.log("View.bindings.#LanguagageCode:update");
LanguageChannel.data.languages.each(function(language){
// Find parent.
var parent = $el.find("#LanguageReadable");
if (language.get("isEditable")){
parent = $el.find("#LanguageEditable");
}
// Select correct value.
var selected = "";
if (language.get("Code") == val){
selected = ' selected="selected"';
}
// Add option to optgroup.
parent.append("<option" + selected + ">" + language.get("Name") + "</option>");
});
}
}
},
onRender: function () {
window.console && console.log("View.onRender");
this.stickit();
}
});
/* ----------------------------------------------------------------------------- */
/* Controllers: Manage page behaviour. */
// Books/Controller.js:
BookController = Marionette.Controller.extend({
initialize: function(){
window.console && console.log("Controller.ctor");
var self = this;
self.bookId = "978-1-4493-9268-0"
// Callbacks from data channels.
self.listenTo(LanguageChannel.data.languages, "sync", self.onSyncLanguages);
self.listenTo(BookChannel.data.book, "sync", self.onSyncBook);
// Retrieve data.
LanguageChannel.channel.commands.execute("getLanguages");
BookChannel.channel.commands.execute("getBook", self.bookId);
},
/* Book functions */
onSyncBook: function(){
window.console && console.log("Controller.onSyncBook");
this.showBookAttributes(); // TODO, use : LanguageChannel.data.languages.fetch();
},
showBookAttributes: function(){
window.console && console.log("Controller.showBookAttributes");
new BookAttributesView({ model: BookChannel.data.book }).render();
},
/* Language functions */
onSyncLanguages: function(){
window.console && console.log("Controller.onSyncLanguages")
this.showBookAttributes();
}
});
/* ----------------------------------------------------------------------------- */
/* Aplication.js: Starts the backbone application (main entry point). */
// Book/Application.js
Application = Marionette.Application.extend({
onStart: function(){
window.console && console.log("Application.start()");
new BookController();
}
});
fiddle link to show how to do- of course, in your project, you need to "requirify your several modules".
fiddle link is based on C0b0ll -actually, a colleague- did on stickit usage-yes another jsFiddle link
doing so, the console will log this:
- Application.start()
- Controller.ctor
- LanguageChannel.channel.command.getLanguages()
- Controller.onSyncLanguages
- Controller.showBookAttributes
- View.onRender
- View.bindings.#LanguagageCode:update
- BookChannel.channel.commands.getBook(978-1-4493-9268-ø)
- View.bindings.#LanguagageCode:update
- Controller.onSyncBook
- Controller.showBookAttributes
- View.onRender
- View.bindings.#LanguagageCode:update