I'm using backbone + backbone.localStorage to persist my data, and I get a wrong behavior:
I've got a model settings with one attribute called user
Settings = Backbone.Model.extend({
localStorage : new Backbone.LocalStorage('settingsStore')
});
var settings = new Settings();
settings.set({user: 'USERNAME'});
settings.save();
After this code if I output the settings.attributes data in weinre I get the following:
settings.attributes
Object
id: "3ac78cfb-ad60-1ab8-8391-f058ae9bfcfb"
user: "USERNAME"
__proto__: Object
Then I save the model to the localStorage, clear, and fetch it again:
settings.save();
settings.clear();
settings.fetch();
And the problem is that if I output the settings.attributes, now this attributes are stored inside a nested object:
settings.attributes
Object
0: Object
id: "3ac78cfb-ad60-1ab8-8391-f058ae9bfcfb"
user: "USERNAME"
__proto__: Object
__proto__: Object
And the problem is when I set the user name again in order to modify, a new attribute is added like this:
settings.attributes
Object
0: Object
id: "3ac78cfb-ad60-1ab8-8391-f058ae9bfcfb"
user: "USERNAME"
__proto__: Object
user: "NEWUSER"
__proto__: Object
And if I save this model, and fetch it again I get 2 new objects on the attributes... and it keeps growing each time.
The answer to the question given by fguillen link gives the correct answer to this problem.
You just need to create the model object with a hardcoded "ID" if you want to save it correctly.
After doing this:
var settings = new Settings({ id: 1 });
The save() and fecth() methods are working correctly. Obviously you have to take care not repeating 2 ID's...
Related
I have a question about to insert object in firestore in angularfire:
My object Person.ts
name: String
age: Number
//--constructor--
//--getters and setters--
if I do this, insert ok: (BUT is this good practice?)
[person.component.ts]
this.db.collection("person").add({
name: this.person.$nome,
age: this.person.$email
})
...
but if I try:
[person.component.ts]
this.db.collection("person").add({
Person: this.person
//or this this.person
})
I get this error in browser console:
Function DocumentReference.set() called with invalid data. Unsupported field value: a custom Person object (found in field Person)
at new FirestoreError (error.js:149)
at
Firestore only accepts a JavaScript object embedded within a document if it is a “pure” object, this means you can't use custom objects while coding with TypeScript.
Change your code to:
this.db.collection("person").add(Object.assign({}, this.person));
Got a server returning a JSON object like so:
{
'key1':'value'
'key2':{
'key2_0':'value'
}
}
And a collection:
var Collection = Backbone.Collection.extend({
url:api.url//which returns the object above
});
var collection = new Collection();
collection.fetch({
success:function(data){
//do something
}
});
Now i need to use certain properties of the collection throughout my application, but say i need key1, i always have to do collection.at(0).get('key1');//returns 'value', because the data returned is stored within the collection, in a new Array at key 0.
Question:
How to directly... collection.get('key1')//now returns undefined... because it is.
I know i could expose an object to the global scope in the collection success function some_other_var = data.toJSON()[0] and access the some_other_var properties directly, but that's not what i'm looking for;
In order to use the get() function from a Backbone.Collection you need to know the model id or cid wanted.
For instance, lets say your data coming from the server is like follow:
[{
id: '123',
name: 'Alex'
}, {
id: '456',
name: 'Jhon'
}]
In that case you can do this:
this.collection.get('123').get('name') // Return "Alex"
Keep in mind that collection is just a set of model, so behind the scenes by doing collection.get() you are getting a model
Tip: If you don't have any kind of id in your server data, there is always the option of using underscore methods:
find
filter
some
contains
etc
It seems like you're trying to ascribe attributes to a collection, but a collection is merely a set of models. Having additional data that is constant throughout the collection suggests that it should be wrapped inside another Model, which is demonstrated here: Persisting & loading metadata in a backbone.js collection
Suppose I have following Backbone.js model:
class App.Models.Article extends Backbone.Model
defaluts:
id: ''
name: ''
tags: []
and a view to display its contents. In a master view I create an instance of article view by passing a newly created Article as :
v = new App.Views.ArticleView({ model: new App.Models.Article() })
and render it to the page.
In the article view and by user interaction some tags are added to the tags array by following code:
addTag: ->
tags = #model.get('tags')
tags.push({id: '', name: 'foo'})
tags.push({id: '', name: 'bar'})
So far so good! Then I close the article view and render another view. Later I want to again render the article view so the code:
v = new App.Views.ArticleView({ model: new App.Models.Article() })
runs again.
The problem is after rendering, I still can see previously entered tags in the tags array i.e. if inside articles view, I write:
console.log(#model.get('tags'))
it will output two objects added before. I expect that each instance has its default values when created not something that there is no more reference to it. Any ideas? Any issues with Coffescript?
P.S. I hope the problem statement is clear enough :)
Don't use arrays and objects in defaults, they will get shared across model instances. If you want tags to be empty array, add that in initialize function.
var MyModel = Backbone.Model.extend({
initialize:function(){
this.set('tags', [])
}
})
Solved!
The problem is that Coffeescript attaches default to the prototype, so defining the defaults as follows solves the problem:
defaults: ->
id: ''
name: ''
tags: []
Again it is attached to the prototype but as a function, it returns an empty object for each call.
Hi im trying to output every "lat" field from my collection. However anything i do returns the right number of results but they all say undefined, the data is definitely there and the names are definitely right. I've tried using pluck and _.each with a get inside the function and all it ever says is undefined.
This is the current method im trying
var ccLocal = window.router.carsCollection;
_.each(ccLocal.models, function(model) {
console.log(model.lat);
})
logging ccLocal returns the entire collection with all its data so its definitely there. What am i doing wrong?
Using model.get("lat") also fails.
Using console.log(ccLocal.at(0).attributes); returns this
Object {unitID: "03_Cow_30", positionHistory: Array[1]}
positionHistory: Array[1]
0: Object
estimatedSpeed: "39"
isToday: false
lastSoundFileName: "F11"
lastSoundRange: "11"
lastSoundTime: "2008-10-29 20:38:25"
lat: "51.466227"
long: "-0.491647"
minutesAgo: 1016726
status: "1"
time: "2011-07-13 16:03:37"
__proto__: Object
length: 1
__proto__: Array[0]
unitID: "03_Cow_30"
__proto__: Object
Ah, so your model attributes data structure is not what everyone thought. Based on your attributes structure, you need something like this. It's a bit fragile due to assuming positionHistory is an array with at least one element, but that's where your data is.
var ccLocal = window.router.carsCollection;
_.each(ccLocal.models, function(model) {
console.log(model.get('positionHistory')[0].lat);
})
Using backbone.js and trying to get data from postsList array I got this in chrome console.log
d {length: 0, models: Array[0], _byId: Object, _byCid: Object, constructor: function…}
_byCid: Object
_byId: Object
length: 9
models: Array[9]
__proto__: f
When I'm trying to use console.log(postsList.length) I get 0, but there are 9 models inside. I don't know how to get number of them.
Yes, this is strange behaviour :)
Chrome displays object preview immediately after you have used console.log.
When you entered console.log(collection) it was empty (probably you have fetched model from the server). But at the moment when you expand the object in console Chrome displays actual object params at current moment.
Try this in console:
var object = {key1:{prop:true}};
console.log(object)
object.key2 = true;
console.log(object)
To get collection length use this way:
collection.fetch({context:collection}).done(function() {
console.log(this.length)
});
EDIT
No-no-no :)
Use this.length instead of this.lenght.
collection.fetch({context:collection}).done(function() {
// equals to this.length
console.log(this.size());
// get all models from collection (array of Backbone.Models)
console.log(this.models);
// get all models from collection (like simple array of objects)
console.log(this.toJSON());
// get model with index 1
console.log(this.at(1));
// get model data with index 1
console.log(this.at(1).toJSON());
// get model with id `some-id`
console.log(this.get('some-id'));
// get models data where property `id_str` equals to `292724698935070722`
console.log(this.where({id_str:'292724698935070722'}));
});
For more information look here:
http://backbonejs.org/#Collection
I think Vitaliys answer is a little bit dangerous, because the passed option {context: collection} is:
a) not mentioned in backbones documentation
b) handled deep down in jQuery when fetch triggers some Ajax-call.
Instead the length of the fetched collection can be easily checked in the success- and error- callback of fetch, e.g.:
someCollection.fetch({
success: function(collection) { // the fetched collection!
if (collection.length) {
// not empty
} else {
// empty
}
}
});
See http://backbonejs.org/#Collection-fetch