Backbone Models - extracting names at runtime - backbone.js

I need to be able extract a backbone model's name at runtime from a backbone View to write generic View and then Template code. That is: I need to get the "ClassName" from the model that is passed to the View and then take the first three characters from it and pass it on to the template.
Is there a simple way to do it?
Thanks.
Bharat

By ClassName, do you mean the name by which you refer to your model, such as User in new User();?
If so, unfortunately this is not possible, because the name you give to the model class is simply a variable name and not part of the model declaration. Consider:
var Foo = Backbone.Model.extend({});
var Bar = Foo;
Is the ClassName Foo or Bar?
Instead, simply give each of your models a name property:
var Foo = Backbone.Model.extend({
name:"Foo"
});
This way you can easily get the model name, either by modelInstance.name or ModelClass.prototype.name.

Related

What does the "r" mean in chrome dev tools when you're looking at a Backbone Object?

I'm learning backbone and using chrome devl tools to look at objects in my browser. What does the 'r' mean?
It's the name of the constructor used to create the model object. However in this case the Backbone code has been minified.
If you create an instance of the base Model class it will be logged like this:
If you look at the Backbone source code you can find the constructor definition:
var Model = Backbone.Model = function(attributes, options) {
However, if your code is compressed the object will instead show up like this:
In your case you're using Backbone's extend mechanism to create a new model type that inherits from the base Model.
Uncompressed this will show up like this:
Again, we can look at the Backbone source code to understand why:
var extend = function(protoProps, staticProps) {
// ...
child.prototype.constructor = child;
// ...
return child
}
You can see that when the new model type is created Chrome doesn't have access to the name you want to use for the model. Instead it tries to do its best to infer the correct name from the variable names.
And then, after compression, you get the single-character class name that you are seeing in the console:

Backbone.js: Why can't I retrieve the model in this case?

I'm trying to retrieve the model, because I need to access certain attributes, but I cannot. I'm inside a view, which extends another one. This is how the view looks like:
var ImageGridControlView = GridControlView.extend({
//.... stuff ....
alert(this.model.get('property')) //This gives me an error in console and nothing is alerted.
});
In the class that the above code extends, the model can be retrieved, like this:
var GridControlView = ControlView.extend({
//.... stuff ....
alert(this.model.get('property')) //This shows the property value correctly
});
Why can't the model be retrieved from ImageGridControlView? What is the persistence of models across different classes, children, etc? I'm new to Backbone, and the official documentation only covers models superficially.
Your snippets are too small to actually find the problem, so we have to just guess. Most likely candidates are:
you are accessing this.model inside a function triggered by an event binding that is not properly bound, so this isn't actually your view instance. It could be a the source DOM element of the window object instead.
You aren't passing a model property in the options object provided to the view's constructor

Get rid of surrounding elements in Backbone.Marionette

I have the following view:
return Marionette.ItemView.extend({
el: '<section>',
template: JST['app/scripts/templates/grid.ejs'],
that is called like this:
// a Layout
regions: {
grid: '#grid',
detail: '#detail'
},
onShow: function () {
var detailModel = new DetailModel();
var g = new GridView(detailModel);
this.grid.show(g);
}
The question is: How do I get rid of the surrounding section element ? I tried to omit the el property but that gives me the following strange looking div:
<div productname>
Regards Roger
The surrounding element is required for backbone to work. It is essentially a container/placeholder for your view to sit in, whether its contents have been rendered or not.
If you really insist on not having the container then I would consider resorting to the following:
https://github.com/marionettejs/backbone.marionette/blob/master/docs/marionette.region.md#set-how-views-el-is-attached
Marionette.Region.prototype.open = function(view){
this.$el.empty().append(view.$el.children());
}
I say 'resorting' because, in my opinion, this is not how Backbone is supposed to be used and may have side-effects. (im not quite sure what will happen when the view in that region tries to re render; what will it's el element be pointing to?)
To expand on Scott's answer, it's probably a very bad idea to try and force the removal of the surronding view tags.
All Backbone views are contained within an DOM element. Given this fact, you have 2 main options:
have Backbone put your view into the default div element
specify which element you want Backbone to wrap your view with, using the el or tagName attributes
If the "extra" tags are creating issues (e.g. you need to generate a specific HTML set for use with a plugin), then you're not defining the wrapping element properly. For more on the subject, take a look at this blog post of mine: http://davidsulc.com/blog/2013/02/03/tutorial-nested-views-using-backbone-marionettes-compositeview/
Edit based on jsFiddle: the reason for your strange behavior is that you were passing a model instance to the initialize function. This is then interpreted as attributes for the view and get set as HTML attributes.
The correct way to provide a model instance to a view is :
new App.FooterView({
model: new App.Model()
})
In other words, you provide a javascript object to the view, with a model property. If you want to learn Marionette basics quickly, check out the free preview to my book: http://samples.leanpub.com/marionette-gentle-introduction-sample.pdf (You'll find how to instantiate a view with a model on pages 15-21)

How to update model in collection?

I have the following Backbone.js collection:
var Tags = Backbone.Collection.extend({
url: "/api/v1/tags/"
}),
How do I update one of the models in the collection so that it posts to /api/v1/tags/id and saves the data for that model.
So if I change name of model with id 2 in the collection
It should PUT to
/api/v1/tags/2 with the following data:
name: new name id: 2
I've also recently wanted to update particular model in the collection. The problem was that if I did use just model.save it didn't update the collection. The goal was to change the model in collection, change it on the server, update collection accordingly and not use the sync method. So for example I have my variable collection and I want to change the model with id = 2. So the first thing, I will create an instance model, like this: var model = collection.get(2)Then I will update the attributes on this particular model:model.set({name: 'new name'})Then I will save it to the server:model.save({}, {url:'/api/v1/tags/'+model.get('id')})Then we have to update collection accordingly to the changes:collection.set({model},{remove: false})set method - it's a 'smart' update of the collection with the list of the models you passed in parameters. remove: false parameter - it's a restriction for a collection to remove existing models in collection. More here.
The first thing you can miss is that in your corresponding Tag model you'll need to set "urlRoot" to match the Collection's "url". Otherwise it doesn't know about the collection at all:
var Tag = Backbone.Model.extend({
urlRoot: "/api/v1/tags"
});
var Tags = Backbone.Collection.Extend({
model: Tag,
url: "/api/v1/tags"
});
This is useful if you want to save the tag separately:
var tag = collection.get(2);
tag.set({key: "something"});
tag.save(); // model.save works because you set "urlRoot"
On the collection, "create()" is also "update()" if id is not null. That's not confusing. :) Therefore, this is pretty much equivalent to the previous sample:
collection.create({id: 2; key: "something"});
This will update the existing tag with id=2 and then trigger a PUT.
This is an ancient question; answering because I was searching for the same answer--you've probably long since solved this problem and moved on. :)
You can pass variables to the save method. It accepts all the options which jQuery's ajax method uses (unless you overrided Backbone.Sync)
You could do something like:
model.save( { name:'new name' } );
The id and PUT method will automatically be added by Backbone for you.

Backbone.js model property constants - is this good practice?

I have trouble keeping track of the properties of a Model instance. For example I have declarations such as:
MyModel = Backbone.Model.extend({});
Then in my views, I'm often doing something like:
var someVal = this.model.get('someProperty');
I was beginning the task of moving a View's strings into constants by encapsulating them in an object and passing it as a second parameter to a View's constructor, for example:
SchemaOptionsView = Backbone.View.extend(
{ /* Body of View here as usual */},
{
TEMPLATE: '#View-Template',
INPUT_REQUIRED:'required'
});
When I got to thinking, I could solve two problems by doing this with my Models:
MyModel = Backbone.Model.extend(
{ /* Body of Model here as usual */},
{
PROPERTY_1 = 'p1',
PROPERTY_2 = 'p2'
});
I could then use the constant to retrieve the property value:
var someVal = this.model.get(MyModel.PROPERTY_1);
This would allow me to clearly see the properties a Model instance contains, and also moves a string value into a constant in an appropriate place.
I have not seen this recommended or in any examples. Have I missed something? What do people think about this idea?
This is solving a non problem. Your models should have well defined attributes - we use the defaults hash to enumerate all the available attributes of our models. Not only does this provide a catalog of the attributes that a model possesses but it also provides a way to override a non-validated input.

Resources