Listing instances of a Model in Backbone application - javascript

In my Backbone application I have a Model. Is there a way of getting all instances of this Model in the app if not all of the instances belong to same Collection? Some of the instances might not belong to any Collection at all.
WHY do I need to do this?
I have a namespaced models (let's say Order.Models.Entry). This is the model of the instances I am talking about. There are some collections like Order.Models.Entries that contain instances of Order.Models.Entry type. But instances get to this collection only when they are selected (with a certain attribute). Before being selected the models are just… well… models.
UPDATE
Obviously I could load every model I create to some allModels collection as it has been suggested in the comments. But the question is not really about a workaround but about exact lookup. The reason why I would like to avoid adding models to an uber-collection is that most of the models will be added to different collections anyway and I just wanted to avoid creating dummy collection for just tracking purpose.

No. There are a couple of good design reasons why you shouldn't be doing it. (encapsulation, not polluting the global scope, etc...)
If you still wish to have this solution you could just maintain a Gloabl list and have your Backbone.Model insert itself into this list, here is a quick solution:
var allMyModels = [] ;
var MyModel = Backbone.Model.extend({
initialize:function(){
allMyModels.push(this);
// Some more code here
},
// also if you wish you need to remove self on close delete function
});
var x = new MyModel();
var y = new MyModel();
in the end of this code, allMyModels will have both models

Why don't you create a Collection (we'll call it allModels) and each time a model is created, do: allModels.add(model). That way, you can access the models, and if you destroy one it will remove itself from the collection.

Related

Knockout mapping plugin [create, update]: objects created, cannot update

I've posted my code here: http://jsfiddle.net/HYDU6/6/
It's a pretty stripped-down version of what I'm actually working with, but captures the essence of my problem. My view model is like so:
var viewModel = {
objects: {
foo: [
{ text: "Foo's initial" },
],
bar: [
{ text: "Bar's initial" },
]
}
}
I'm using the ko.mapping plugin and my create handler for objects instantiates Obj from objects.foo and then objects.bar, returning the resulting two items in an array. This part works fine; I use
var view = {};
ko.mapping.fromJS(viewModel, mapping, view);
My issue is updating based on new data. (i.e., getting data from the server). I have an object of new data and I attempt
ko.mapping.fromJS(new_model, mapping, view);
I suspect this is incorrect but I have not been able to get it working despite extensive searching. (Trust me, it's been days. ): Anyway, thanks for any help.
EDIT: So I've mostly figured it out - I was depending too heavily on mapping.fromJS and certain things were not being wrapped into observables. I also realized that I didn't need the create(), only the update(), as it is called after create() anyway. If you have a similar problem let me know!
John,
When updating your data using ko.mapping be sure you don't create a new item. Your UI is already bound to the existing items, so you just want to update the values of the existing item properties; not create new ones. For the example you posted, you'll want to adjust your "update" method of your map to insert the new values into the correct ko.observable property, rather than creating a new object in it's place. The ko.mapping "update" method has a few different parameter lists depending on usage, with the third parameter being the target object of the map. You would want to update that object's properties.
obj.target[label].items[0].text(obj.data[label][0].text);
But, that's a bit of a mess. You'll probably want to create a second level of mappings (create / update) to handle "deep" object hierarchies like in your fiddle. For example one map for objects at the "foo/bar" level, and another call to ko.fromJS from within "update" with another map for the child Obj() objects.
After fixing that, you'll run into a couple simple binding errors that you can fix using another "with" binding, or a "foreach" binding for the child arrays.
Overall, you've just run into a couple common pitfalls, but nothing too severe. You can learn a bit more about a few of these pitfalls on my blog here : http://ryanrahlf.com/getting-started-with-knockout-js-3-things-to-know-on-day-one/
I hope this helps!

How does map work with a Backbone collection?

Goal: I am trying to create a case insensitive search that goes through my collection and tries to match the user query against model's name attribute. Right now if I want to find a specific model, the search query must be exact.
It seems there is no easy way to do something so simple in Backbone, not out of the box. The function map came to mind. What if I could go through the entire collection and change model's name attribute to lower case, then change user query to lower case as well and voila!
But the problem is I have no idea how to use Backbone Collection and map function. There is no documentation on map in Backbone docs, other than a link that leads you to underscore documentation with a super primitive example code using an array of three numbers.
This does not work...why?
this.collection.map(function(model) {
return model.get('name').toLowerCase();
});
Actually, all of underscore's collection methods are proxied on Backbone.Collection objects. when you do a collection.map(... it returns an array of objects returned by the mapped function. The solution presented by raina77ow does not work since a Backbone.Collection is not an array and assigning the result of the map to this.collection will destroy the collection itself.
If you want to filter a collection, I would recommend using the filter method. ( I assume you are working from a Backbone.View:
var filter = this.$('#search-field').val(),
filteredModels = this.collection.filter( function( model ) {
return model.get('name').toLowerCase() === filter;
};
this.collection.reset( filteredModels );
Note that any of underscore's proxied methods on collections will return an array of models. If you then want to use them, you can reset the collection with these models or, equivalently, set the collection's models attribute to the filtered results: this.collection.models = filteredModels. The first form has the advantage of triggering a reset event on the collection to which you can listen to and, for example re-render your view.

nodejs jugglingdb belongsTo and hasMany relations with existing db objects

jugglingdb exposes two functions to create relational dbs:
belongsTo
and
hasMany
i now aks myself how i might use this in daily development.
belongsTo and hasMany are adding functions to the objects,
but as it seems there is no way to create relations between existing objects?
see:
http://compoundjs.com/juggling.html#hasMany
for an example.
i would like to not create the object but instead create linkages between existing objects,
how will that work?
maybe i am just misinterpreting the functions?
have fun
jascha
ps:
would be great if someone with 1500+ rep could create the jugglingdb tag and add it to this question? i really cant say if its relevant enough though.
When you, i.e. want to add articles for an existing author, you can do it like the following:
User.find(uid, function(err, user) {
var article = user.articles.build({articleName : 'Article Foo'});
article.save();
});
That will automatically create a foreign key for user inside the new created article.

For Loop over Backbone Collection

Fairly new to backbone, so this is a really basic question. I have a Backbone collection passed into a function and I can prove that it has been passed and that the models in the collection have ids.
Here's how I'm setting the ids -
convertToMapObjects: (results) =>
objectList = new ObjectList()
results.each(result)->
testObj = new TestObject()
testObj.set
id = result.get("id")
objectList.add(testObj)
And in another function ( accessed through making the model trigger an event) -
getIds: (objects) =>
ids = (object.id for object in objects)
I think the issue may be because of how I'm iterating through the collection because when I tried doing
for object in objects
console.log(object)
I saw two undefineds. Is this correct? If so, why can't I use a for loop to go through a backbone collection? Also, is there a way I could do so?
A Backbone collection is not an array so for ... in won't produce the results you're expecting. You want to look at the collection's models property if you want to use a simple loop.
However, Backbone collections have various Underscore methods mixed in:
Underscore Methods (28)
Backbone proxies to Underscore.js to provide 28 iteration functions on Backbone.Collection. They aren't all documented here, but you can take a look at the Underscore documentation for the full details…
forEach (each)
...
So you can use map or pluck if you'd like to avoid accessing the models property:
ids = objects.map (m) -> m.id
ids = objects.pluck 'id'
The pluck method is, more or less, just a special case of map but collections implement a native version rather than using the Underscore version so that they can pluck model attributes rather than simple object properties.
You want to loop over the models property of the collection, not the collection object itself.
for object in object.models
This will give you a model in the collection

How to structure nested Models and views?

Using backbone.js:
I have a collection of ModelA that contains several attributes and also one "node" that holds several ModelB. ModelB also contains several attributes.
CollectionA
ModelA
Attribute 1
.
.
Attribute n
"Node"
ModelB
Attribute 1
Attribute 2
ModelB
Attribute 1
Attribute 2
ModelA
Attribute 1
.
.
Attribute n
"Node"
ModelB
Attribute 1
Attribute 2
ModelB
Attribute 1
Attribute 2
I'm still working on the views but the main idea is that the views should be structured in a similar way. (Collection View holds several View A that holds several View B). The same ModelB will never be shared between multiple ViewB.
Q1: Does the design make sense or is it any obvious flaws I should consider? (This is my first try with BackboneJs).
Q2: What is the best way to set up the "Node"? Right now I'm using an array of ModelBs. Is it possible to have a collection of ModelB on each ModelA instead? Which approach is better?
Any guidelines are appriciated!
I would also like to point out that I've read this excellent post on a related issue (recommended). That case did however not contain ModelB in a array/collection in the same way as this one does.
Q1: Does the design make sense or is it any obvious flaws I should consider?
Design Assumptions: Collection A has many Model As, Model A has Collection of Model Bs, each Model B has it's own View B.
Q2: Possible to have a collection of ModelBs on each ModelA?
Answer: Doable.
It's fairly common for models to have a bunch of related sub-models "in" them. You can definitely go about it by creating (like you mention) an array, an object, a collection to hold those Model Bs (let's call it the container.) The basic way would be just to create the container and then instantiate new models and plug them in. Most likely you want some kind of reference in those Model Bs to the related parent Model A so that you can return to that state later. Like each Model B has a ModelA_ID as an attribute.
This might be a good use of Paul Uithol's Backbone-Relational.
With Backbone-Relational, you can setup your Model (class) and define it in such a way that it has a collection of Model Bs. Here is what the code looks like.
ModelA = Backbone.RelationalModel.extend({
relations: [{
type: Backbone.HasMany,
key: 'modelBs',
relatedModel: 'ModelB',
collectionType: 'ModelBCollection',
reverseRelation: {
key: 'parentA'
}
}],
defaults: ...,
initialize: ...,
etc. ... // Other instance properties and functions of model.
});
When you do this, every model A that you instantiate will have a collection of Model Bs that can be referenced through the ModelA attribute modelBs. Or any key you designate.
Here is what it looks like to instantiate the ModelA.
myModelA = new ModelA({
// Setting up ModelA attributes...
'modelBs': [1, 3, 7]
});
I've instantiated the ModelA and along with setting the other attributes you may have defined, I'm also setting up the the value for attribute modelBs of ModelA. This is an array of ids of each ModelB that is related to ModelA. This is how your collection knows which ModelBs are associated to this ModelA.
myModelA.fetchRelated('modelBs');
Your .fetchRelated() call sends a request to the server to populate the modelBs collection with ModelB 1, 3, and 7.
When you want to access the collection of ModelBs in ModelA, you would simply do something like this.
myModelA.get('modelBs');
This returns the collection of ModelBs related to that ModelA assuming you've fetched the related models and the collection has ModelBs in it.
The nice thing about Backbone-Relational is that it makes it easy to establish these defined relations automatically, on instantiation of the parent model. It also creates the reverse relation so traversing up and down from parent to child, child to parent is easy.
If I were manipulating ModelB and wanted to get to ModelA, I use the reverseRelation key I established parentA.
someModelB.get('parentA'); // Points to the related ModelA
It also helps with bindings and some other problems that prop up when you have models in models in models. Relational works well with one to one, one to many and inverse relationships. There is a workaround with many to many but I don't think it's common because it's a difficult proposition with the way things are set up.
As for views, I'm not sure exactly what you're thinking but do you need to have a "collection" of views?
Let's say you have ModelA with a collection of ModelBs. Each ModelB has an associated view. This is illustrated very nicely with the concept of the old-fashioned LIST.
<div id="ModelAView">
<ul>
<li>ModelB_1</li>
<li>ModelB_3</li>
<li>ModelB_7</li>
</ul>
</div>
While there are a bunch of ModelBs, you already have them nice and tidy in a collection. If you go with a data driven way of managing your views, there is no need to put the view objects in another list. Instead, you can make them self managing!
// Assume when you instantiate ViewB, you pass to it a ModelB.
ViewB = Backbone.View.extend({
initialize: function() {
this.model.bind('remove', this.remove, this);
this.model.bind('update:colorAttr', this.updateColor, this);
},
updateColor: function() {
this.$el.css('color', this.model.colorAttr);
}
});
Now say you get rid of ModelB from your collection.
myModelA.get('modelBs').remove(someModelB);
Then the view associated with this modelB will automatically be removed from the view.
Not sure if this is what you had in mind. I usually go with this approach. Anyway, if there are more specifics just post em in the comments. Hope this helps.

Categories

Resources