I am developing a rich client application using Backbone.js and have encountered a situation where I need to fetch 3 values from three database tables and display them.
The rub, however, is that they are not part of my models and I have no need to synchronize them. They are for display purposes only. Should I created a child view which adds them to the DOM as part of the render() method? I'd prefer not to just hack some jQuery code together -but- it doesn't seem to fit nicely into my mental picture of Backbone models and views either.
The rule of thumb in MVCs like Backbone is that the data structure should always be stored in the model layer imo. In your case this could either mean extending your current models with those ui state related attributes (recommended) or create a new model and pass it to the views as an option:
var myModel = new MyModel();
var newModel = new NewModel();
var myView = new View({
model: myModel,
newModel: newModel
});
later in the view you can access to the newModel as this.options.newModel
Related
I've the following backbone model.
var Credential = Backbone.Model.extend({
defaults: {
user: null,
password: null
}
});
I want to bind this model to a view.
Is it a best practice to instantiate the Credential model from the router and pass to the view
var loginView = new LoginView({ model: new Credential() });
or instantiate the model in the initialize method of the LoginView.
var LoginView = Backbone.View.extend({
initialize: function() {
this.model = new Credential();
}
});
The best practice is to assign a model to the view, an not let the view create the model.
Conceptually, a view is one representation of a model, when you can have multiple views representing the same model (for instance a form, and a list).
This is why keeping them loosely coupled and assigning a model to a view is usually a better pattern.
There is also one way you can follow. As you may know, backbone view share Controller task from MVC. So you may detach Controller responsibility from view in a independent abstraction, like it made in Marionette.js framework. It this case you will have workflow as following:
1) Controller is in charge of creating and delete views and models, models fetch, providing models to views.
2) Views listen to model events, DOM events and render actual model data
3) Model is only in charge of working with data
I'm not sure what the right approach here is. I am setting up a simple form. I need a couple of standard HTML input fields and a couple of select inputs. The data is coming from a couple of different sources and I would like to present the models and collections, with their data to the view like so:
Controller:
var registerView = new registrationView.RegistrationForm({
model: userModel,
model2: departmentCollection
});
myApp.SomeRegion.show(registerView);
Can I do this? Or do I need to split the form into separate regions, all with their own model or collection. If so, how do I call the model data in the template. I have not been able to make it work so far. I cannot find any examples of a form with mixed fields coming from different models and collections,
Many thanks
Wittner
You can do it using a composite view:
var registrationView.RegistrationForm = Marionette.CompositeView({
// ...
});
var my View = new registrationView.RegistrationForm({
model: userModel,
collection: departmentCollection
});
See https://github.com/marionettejs/backbone.marionette/blob/master/docs/marionette.compositeview.md and https://github.com/marionettejs/backbone.marionette/blob/master/docs/marionette.collectionview.md (a composite view inherits behavior from a collection view).
Usually I have a View on which I set listeners to model-changes, like so (conflated):
var jsonModel = {bla: 'interesting stuff'}; //some model in json, probably rendered in a dom-element and passed from the server to the client
var someModelType = Backbone.RelationalModel.extend({
bla: "String"
});
var someModelInstance = new someModelType(jsonModel);
var someViewType = Backbone.View.extend({
initialize: function(){
this.listenTo(this.model,'change:bla', function(model){
//update view to sync with model change here
}
}
});
var someViewInstance = new someViewType({
model: someModelInstance
});
I'm looking for the preferred / backbone - way of bootstrapping the view, i.e: I want my view (form fields or what have you) to be synced with the model on creation. With the above this is impossible since the model is created before the view is attached, which results in model-updates/changes to be fired before listeners from the view were initialized.
Of course I could code some custom bootstapping logic which would call the listener-functions manually, but since this must be such a common problem, I'm looking on some best practice advice, or even better, a Backbone-switch I need to set to get this to work.
This will sound silly, but what I usually do is do a render() after the view creation.
For me, the whole point of the change event is to notify of a change. The fact that it's triggered also on creation (as a "changed compared to the default") is more a side effect than anything deep...
In that sense, when I create the views, and give it an existing model, I expect the model to be somewhat ready and so I should be able to do a render() right away. So my bootstrapping code would be more like:
var someViewInstance = new someViewType({
model: someModelInstance
});
someViewInstance.render()
Or do it in the initialize() after bindings if you feel adventurous (I personally don't like that because when dealing with subviews, it's hard to know exactly when you want the render to happen, especially when dependent on libraries who need the DOM to be ready, and can't work on detached nodes).
So to sum up, although your problem is common, to me, it doesn't need any kind of complex solution: you have a render() function to transform your model into DOM-stuff, your model may or may not be ready but it exists, so you pass it to the view, and you do the first rendering after creating the view, manually, because you know it needs to happen. Then you bind to changes, in case your model is updated, to update the DOM accordingly.
side note: in case of a collection of models, when the Model isn't ready at ALL, then it probably shouldn't even have an instance, and you should let the Collection give you some add/remove events for when it pops into existence.
I am new to Backbone.js and I have the following problem: I have multiple views that uses the same model. I do not want to re-fetch model on every view render, but I want to fetch it only once and then when view is rendered use that instance/data.
My example: I have 3 views for user. One is some user statistics, another user info and third user profile. After login user lands on user profile view and there I fetch the user model but how could I then pass this model reference around or even better how could I access that model data from different views?
I hope I am not doing any anti-pattern here. I have seen a lot of examples with binding events to model change and then rerender all the views but that is not my case. I am using backbone.js with require.js and underscore template engine.
Just return the instantiated model:
define(function (require) {
var MyModel = Backbone.Model.extend({})
return new MyModel()
});
I'm new to Backbone and I don't fully understand it yet, and I've come across a situation I can't find any documentation on. What I if I have a view that contains multiple views? For example, I have a view called StackView. The purpose of this view is to neatly lay out a set of cards. It manages the animation of adding, removing, and adjusting cards in the stack. Each card is a CardView. How would I handle this? I've seen people talk about views within views by simple creating a variable in the view and assigning the View instance to that variable. Should I just be adding an array of CardViews in a variable of a StackView?
That's what I do, and it works well. Here's a snippet of a View I use in an application. I've re-written it back into regular javascript from my coffeescript, so I apologize for any typos:
render: function() {
var _this = this;
this.$el.html(this.template());
this.listItemViews = [];
// for each model in the collection, create a new sub-view and add
// it to the parent view
this.collection.each(function(model){
var view = new App.Views.Projects.ListItem({model:model}); // create the new sub-view
_this.listItemViews.push(view); // add it to the array
_this.$('#project-table tbody').append(view.render().$el); // append its rendered element to the parent view's DOM
});
return this;
}
This lets my Table view maintain a reference to all the listItemView views.
Of course, if you do this, you should make sure to properly remove these child views and unbind any events when you remove the parent view.