I am developing a backbone application which is using require.js.
I want a user to enter in the ‘id’ for a model and then either be redirected to a view for that model if it exists, or display an error message if it does not. This sounds extremely simple, but I am having trouble figuring out the roles of each component.
In the application below, the user will come to an index page with an input (with id ‘modelId’) and a button (with class attribute ‘lookup’).
The following piece of code is the router.
define(['views/index', 'views/myModelView', 'models/myModel'],
function(IndexView, MyModelView, myModel) {
var MyRouter = Backbone.Router.extend({
currentView: null,
routes: {
"index": "index",
"view/:id": "view"
},
changeView: function(view) {
if(null != this.currentView) {
this.currentView.undelegateEvents();
}
this.currentView = view;
this.currentView.render();
},
index: function() {
this.changeView(new IndexView());
},
view: function(id) {
//OBTAIN MODEL HERE?
//var model
roter.changeView(new MyModelView(model))
}
});
return new MyRouter();
});
The following piece of code is the index view
define(['text!templates/index.html', 'models/myModel'],
function( indexTemplate, MyModel) {
var indexView = Backbone.View.extend({
el: $('#content'),
events: {
"click .lookup": "lookup"
},
render: function() {
this.$el.html(indexTemplate);
$("#error").hide();
},
lookup: function(){
var modelId = $("#modelId").val()
var model = new MyModel({id:modelId});
model.fetch({
success: function(){
window.location.hash = 'view/'+model.id;
},
error: function(){
$("#error").text('Cannot view model');
$("#error").slideDown();
}
});
},
});
return indexView
});
What I can’t figure out is that it seems like the better option is for the index view to look up the model (so it can display an error message if the user asks for a model that doesn’t exist, and also to keep the router cleaner). But the problem is that the router now has no reference to the model when the view/:id router is triggered. How is it supposed to get a hold of the model in the view() function?
I guess it could do another fetch, but that seems redundant and wrong. Or maybe there is supposed to be some global object that both the router and the view share (that the index view could put the model in), but that seems like tight coupling.
You can do something like this. You could do something similar with a collection instead of a model, but it seems like you don’t want to fetch/show the whole collection?
With this type of solution (I think similar to what @mpm was suggesting), your app will handle browser refreshes, back/forward navigation properly. You basically have a MainView, which really acts more like a app controller. It handles events triggered either by the router, or by user interaction (clicking lookup or a back-to-index button on the item view).
Credit to Derick Bailey for a lot of these ideas.
In the Router. These are now only triggered if the user navigates by changing a URL or back/forward.
In new MainView, which you would create on app startup, not in router:
Then in IndexView, you trigger the ‘show-item-view’ event with the already fetched model.
I don’t think this is exactly perfect, but I hope it could point you in a good direction.