Why does backbone.js return an empty array when accessing models?

I have a router accessing its collection. The β€œMy” cycle was not repeated using models, so I tried to run the collection to see what it returned. It turns out that when I register a collection directly, I see all the models as expected. But if I try to register the collection model attribute, I get an empty array! It does not make sense. These lines immediately follow each other. I tried changing the order and got the same result.

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 is this going to happen?

Here is the code, as in the router, to give a better context of where this code is run:

 # 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 
+7
source share
3 answers

Jim

This does not fix your problem - you have dealt with it. But that explains why you see the console output that you see.

When you run console.log (this), you output the object itself and links to console links (pointers, if you want) to internal variables.

When you look at it in the console, while console.log (this) launches the model area, it is empty, but while you look at the logs, the collection has finished loading the models and the internal array variable is updated, and the link to this a variable in the object log shows the current content.

Basically in console.log (this), the internal model variable continues its normal life, and the console shows the current status at the time you look at it, and not at the time you called it. Using console.log (this.models), the array is reset as is, the link is not supported, and all internal values ​​are reset one by one.

This behavior is fairly easy to reproduce with a short timeout, see this script. http://jsfiddle.net/bendog/XVkHW/

+5
source

I found that I needed to listen to the collection before reset. So instead of passing the model to the view, I created another view, waiting for the collection, and listened for the reset event to trigger the rendering 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 
+2
source

You can use the promise. (.done will do everything)

 @collection.fetch().done => for model in @collection.models console.log model 

this will give you @collection models extracted and ready to go.

or if you don’t need to force an application to wait,

 @collection.on 'sync', => for model in @collection.models console.log model 

Both of them will allow you to do what you want.

0
source

All Articles