Best practice for declaring views, models etc. in backbone.js - javascript

I've seen backbone views (or models, collections etc), declared like this
var SomeView = Backbone.View.extend({...
I've also seen them declared like this
window.SomeView = Backbone.View.extend({...
Could someone please explain the pros/cons in each case?

Really it does the same thing: http://snook.ca/archives/javascript/global_variable
However http://documentcloud.github.com/backbone/#View-constructor example goes with the first example and would be understood by a larger audience.

Some people prefer to have only one global variable (important for libraries, not so much for normal pages) and use something like:
var MyApp = {
Models: {},
Collections: {},
Views: {}
}
and then for each view:
MyApp.Views.SomeView = Backbone.View.extend({...

Related

Can I create custom methods in Backbone.collections?

Apologies I'm still learning the fundamentals of Backbone.
I'm a little confused about Backbone.collections. I understand that they consist of a group of collections, and can have url and model attributes. Can you define a custom method in a backbone.collection?
For example:
var Books = Backbone.Collection.extend({
url: '/books',
model: Book,
getBook: function(id, options){
......
}
});
Is this possible and if so, what would it do?
Thanks!
This is absolutely possible and a great way to encapsulate functionality specific to that collection. Although typically in practice I find myself expanding the functionality of the Models more.
As far as what it would do... If you had a collection of books you may want to write helper methods for accessing, pruning, or serializing your collection. I'm not sure what your business needs are.
Have look at underscore.js for available collection functions, so you don't reinvent the wheel.
Custom methods on collections would usually do one of two things:
Handle events fired by the models, if you need to trigger custom actions when that happens
Hold reusable looping/filtering/sorting so that you don't have to inline that stuff throughout your application
When I say collections would usually do this, it doesn't necessarily mean that you're doing anything wrong if your methods falls outside of these two categories, this is just to get an idea what kind of logic you might want to put into a collection custom method.
Take your books for instance, let's say you wanted to have a custom method that returns the total number of pages for all of the books in your collection. That could look something like this:
var Books = Backbone.Collection.extend({
url: '/books',
model: Book,
getTotalNumPages: function() {
var numPages = 0;
this.each(function(model) {
numPages += parseInt(model.get("pageCount"), 10);
});
return numPages;
}
});
// Elsewhere in your app
console.log("Total pages: ", books.getTotalNumPages());

Backbone.js and global instances

we're pretty new to backbone and building a new app with it.. we're using the standard namespacing ie:
(function($) {
window.Lara = {
Models: {},
Collections: {},
Views: {},
Events: {},
Templates: {}
};
var vent = _.extend({}, Backbone.Events);
}(jQuery));
We need to keep state of certain views so that they're accessible across the different models and views, my question is where should instances be held of all the models and views etc... I'm finding it hard to keep things within scope between all the events and different views so I could just put all the needed global instances somewhere within the App namespace... is this the right approach?
I feel like the defined Lara.Models, Lara.Views etc should be kept clean and as a template for instances... should I just create an Lara.Instances and dump them all in there?
Any suggestions would be great here!
Not quite sure about your questions, you need refs to your existing views/models?
I would keep an reference for important models like UserSession in the Application scope, for your case, it would be something like
Lara.currentUser = new Lara.Models.UserSession() # Set it when user logs in
Is this something you are looking for? Leve me the comment

Backbone/RequireJS and multiple models

I am having trouble wrapping my mind around primarily RequireJS. I see that it is a good/necessary technology, but implementing it, for me, has been a real stretch. I greatly appreciate your help!
I am trying to develop a fairly flexible application with Backbone and RequireJS. The problem is that I am totally used to syntax like new Person() without having to specify dependencies. Is there an efficient way to use RequireJS with quite a number of models? I think my problem is always working with returns. I considered using a factory method to create the model with the require function, but doing so necessitates that the require function is synchronous, which completely defeats the purpose of RequireJS.
It just doesn't seem right to have to require all of my models first and then include those in the instantiation function - or do I?
Do you have any suggestions or tutorials about how to structure and model an application like this?
Thank you for helping me out!
JMax
You can use what I call require js module pattern. If you know a group of classes are often used together you can do something like this.
First you define each class in a separate file and then you define a module to hold them together
Module.js
define([
'./models/FirstModel',
'./models/SecondModel',
'./views/FirstView',
'./views/SecondView',
'txt!./templates/template.tpl'
], function(FirstModel, SecondModel, FirstView, SecondView, template) {
return {
FirstModel: FirstModel,
SecondModel: SecondModel,
FirstView: FirstView,
SecondView: SecondView,
template: template
}
});
And then when you want to use class from this module you just do
define(['./Module'], function(Module) {
var AView = Module.FirstView.extend({
model: Module.FirstModel,
render: function() {
this.html(_.template(Module.template)(this.model.attributes));
if (something) {
this.$el.append(new Module.SecondView().render().el);
}
}
})
return AView;
});
I don't believe using modules defined with requirejs we should return an instance - we should always return a constructor or an object.
You should totally embrace the defining and requiring - with time you'll start to love it - without having to think much about adding/tracking dependencies etc. everywhere by hand or (so 2005!) having most of the stuff in one file :)

How to organise common code

Just getting started with backbone.js, and one of the things I've noticed is that many of my models, collections and views share some very similar methods. I'd like to refactor them & call them from an extracted location (/lib?). I went searching for documentation and/or examples, and was surprised by how little I found (specifically, none). So, a few questions:
Is there a reason I'm overlooking as to why there are so few examples of backbone methods factored out into common libraries?
Is there a standard/agreed upon location in backbone projects for shared code?
Any backbone classes and/or common plugins to help store common methods?
Any ideas appreciated - thanks in advance.
(EDIT) Example added:
Take this code from a view. (Admittedly it's too short be actually worth refactoring, but its simplicity makes it a concise example)
destroy: () ->
#model.destroy()
#remove()
return false
Suppose I wanted to refactor it into:
destroy: () ->
restful_destroy_method(this)
which then called:
restful_destroy_method: (view) ->
view.model.destroy()
view.remove()
return false
from a common library. Any reason why nobody else seems to do this?
It depends on the situation, and what your common code is.
In the case of your example, what I might do would be to create a more specific View to extend from.
Apologies for the straight JavaScript, I'm not as fluent in CoffeeScript to use it in an answer.
DestroyableView = Backbone.View.extend({
destroy: function () {
this.model.destroy();
this.remove();
return false;
}
});
Then, instead of creating new Backbone.View()s, I'd create new DestroyableView()s. DestroyableView could have other common functions, or you could create several different parent definitions and use _.extend() to apply them all to a single object.
You can use a "Basic View" which own the generic methods :
// Create a Basic View which have all generic methods
var BasicView = Backbone.View.extend({
restful_destroy_method: function () {
this.model.destroy();
this.remove();
return false
}
});
// Create a view which herits the methods of BasicView
var ExampleView = BasicView.extend({
destroy: function () {
this.restful_destroy_method();
}
});
You can show an example on jsFiddle here : http://jsfiddle.net/Atinux/YDMNg/

Passing in functions to Backbone.View.extend

Recently I'm having an argument with some co-workers about something that I
find incorrect.
We're using Backbone in a large application and my way to create views is
the 'standard' backbone way :
var MyView = Backbone.View.extend({
className: 'foo',
initialize: function() {
_.bindAll(this, 'render' /* ... more stuff */);
},
render: function() {
/* ... render, usually
using _.template and passing
in this.model.toJSON()... */
return this;
}
});
But someone in the team recently decided to do it this way :
var MyView = Backbone.View.extend( (function() {
/* 'private stuff' */
function bindMethods(view) {
_.bindAll(view, /* ... more stuff */);
};
function render(view) {
/* ... render, usually
using _.template and passing
in view.model.toJSON()... */
};
return {
className: 'foo',
initialize: function() {
bindMethods(this);
render(this);
}
};
}());
That's the idea in pseudo-code .
Having read the BB source and read tutorials, articles I find this to be a
bad practice (for me it makes no sense), but I'd love some feedback from
other Backbone developers/users
Thanks in advance
One benefit I see from using the closure is providing a private scope for variables and functions that you don't want to be accessible from code outside the view.
Even so, I haven't seen many Backbone apps use a closure to define a view/model/collection etc.
Here's an email from Jeremy Ashkenas concerning this issue as well.
Yes, using closures to create instances of objects with private variables is possible in JavaScript. But it's a bad practice, and should be avoided. This has nothing to do with Backbone in particular; it's the nature of OOP in JavaScript.
If you use the closure pattern (also known as the "module" pattern), you're creating a new copy of each function for each instance you create. This completely ignores prototypes, and is terribly inefficient both in terms of speed and especially in terms of memory use. If you make 10,000 models, you'll also have 10,000 copies of each member function. With prototypes (with Backbone.Model.extend), you'll only have a single copy of each member function, even if there are 10,000 instances of the class.
I totally agree with Paul here. Sometimes you may find it necessary to define methods and properties that are private and can't be messed with from outside. I think it depends wether you need this scoping mechanism in your class or not. Mixing both approaches, with respect to the requirements you have for the class wouldn't be so bad, would it?

Categories