I have a router accessing its collection. My for loop wasn't iterating through the models so I tried logging the collection to see what it returned. Turns out when I log the collection directly I see all of the models as expected. But if I try to log the models attribute of the collection I get an empty array! It doesn't make sense. These lines are directly following each other. I tried changing the order and got the same oute.
console.log(this.collection);
=> Shots
_byCid: Object
_byId: Object
length: 15
models: Array[15]
__proto__: Shots
...
console.log(this.collection.models);
=> []
console.log(this.collection.length);
=> 0
Why would this happen?
Here is the code as it is in the router to give a better context of where this code is firing:
# Routers
class Draft.Routers.Shots extends Backbone.Router
routes:
'' : 'index'
'shots/:id' : 'show'
initialize: ->
@collection = new Draft.Collections.Shots()
@collection.fetch()
index: ->
console.log @collection
console.log @collection.models
I have a router accessing its collection. My for loop wasn't iterating through the models so I tried logging the collection to see what it returned. Turns out when I log the collection directly I see all of the models as expected. But if I try to log the models attribute of the collection I get an empty array! It doesn't make sense. These lines are directly following each other. I tried changing the order and got the same oute.
console.log(this.collection);
=> Shots
_byCid: Object
_byId: Object
length: 15
models: Array[15]
__proto__: Shots
...
console.log(this.collection.models);
=> []
console.log(this.collection.length);
=> 0
Why would this happen?
Here is the code as it is in the router to give a better context of where this code is firing:
# Routers
class Draft.Routers.Shots extends Backbone.Router
routes:
'' : 'index'
'shots/:id' : 'show'
initialize: ->
@collection = new Draft.Collections.Shots()
@collection.fetch()
index: ->
console.log @collection
console.log @collection.models
Share
Improve this question
edited Feb 20, 2012 at 2:26
mu is too short
435k71 gold badges859 silver badges818 bronze badges
asked Feb 20, 2012 at 0:52
Jim JeffersJim Jeffers
18k4 gold badges43 silver badges52 bronze badges
3
- 1 Did the fetch finish and successfully reset or add models to the collection by the time you logged it? – user500198 Commented Feb 20, 2012 at 1:02
- i can only assume it did, the 2 logs are right after each other, it would be a matter of nanoseconds inbetween those two calls. still possible though but it should at least be an unstable result if you test it over a few times... it can't always just be finished loading right inbetween those two log calls. – Sander Commented Feb 20, 2012 at 1:37
- 1 I don't understand why it was logging but I found out that I need to add an event listener on the collection within the view to ensure that it has loaded. – Jim Jeffers Commented Feb 20, 2012 at 2:40
3 Answers
Reset to default 5Jim,
This doesn't fix your problem - you've worked that out. But it explains why you're seeing the console output you see.
When you run console.log(this), you output the object itself and the console links references (pointers if you like) to the inner variables.
When you're looking at it in the console, at the time the console.log(this) runs the models area is empty, but at the time you look at the logs, the collection has finished loading the models and the inner array variable is updated, AND the reference to that variable in the object log shows the current content.
Basically in console.log(this),inner models variable continues its normal life and the console shows the current status at the time you're looking at it, not at the time you called it. With console.log(this.models), the array is dumped as is, no reference is kept and all the inner values are dumped one by one..
That behaviour is quite simple to reproduce with a short timeout, see this fiddle.. http://jsfiddle/bendog/XVkHW/
I found that I needed to listen for the collection to reset. So instead of passing the model into the view I created another view expecting the collection and listened for the 'reset' event to fire 'render' for the view.
# Routers
class Draft.Routers.Shots extends Backbone.Router
routes:
'' : 'index'
'shots/:id' : 'show'
initialize: ->
@collection = new Draft.Collections.Shots()
@collection.fetch()
index: ->
view = new Draft.Views.Desktop(collection: @collection)
# Views
class Draft.Views.Desktop extends Backbone.View
el: $("body")
initialize: ->
@collection.on("reset",@render,this)
render: ->
console.log @collection
console.log @collection.length
You can use a promise. (.done will do fine)
@collection.fetch().done =>
for model in @collection.models
console.log model
this will give you @collection's models fetched and ready to go.
or if you don't need to force the app to wait,
@collection.on 'sync', =>
for model in @collection.models
console.log model
Both of these will let you do what you want.