Backbone.js Empty Array Attribute

arrays, backbone.js, javascript

Solution

Be careful about trusting the console, there is often asynchronous behavior that can trip you up.

You're expecting `console.log(x)` to behave like this:

- You call `console.log(x)`.

- `x` is dumped to the console.

- Execution continues on with the statement immediately following your `console.log(x)` call.

But that's not what happens, the reality is more like this:

- You call `console.log(x)`.

- The browser grabs a reference to `x`, and queues up the "real" `console.log` call for later.

- Various other bits of JavaScript run (or not).

- Later, the `console.log` call from (2) gets around to dumping the current state of `x` into the console but this `x` won't necessarily match the `x` as it was in (2).

In your case, you're doing this:

console.log(this.attributes);
console.log(this.attributes.widgets);

So you have something like this at (2):

         attributes.widgets
             ^         ^
             |         |
console.log -+         |
console.log -----------+

and then something is happening in (3) which effectively does `this.attributes.widgets = [...]` (i.e. changes the `attributes.widget` reference) and so, when (4) comes around, you have this:

         attributes.widgets // the new one from (3)
             ^
             |
console.log -+
console.log -----------> widgets // the original from (1)

This leaves you seeing two different versions of `widgets`: the new one which received something in (3) and the original which is empty.

When you do this:

console.log(_(this.attributes).clone());
console.log(_(this.attributes.widgets).clone());

you're grabbing copies of `this.attributes` and `this.attributes.widgets` that are attached to the `console.log` calls so (3) won't interfere with your references and you see sensible results in the console.

That's the answer to this:

It's showing that widgets is not empty when logging `this.attributes` but it's shown as empty when logging `this.attributes.widgets`. Does anyone know what would cause this?

As far as the underlying problem goes, you probably have a `fetch` call somewhere and you're not taking its asynchronous behavior into account. The solution is probably to bind to an `"add"` or `"reset"` event.

Problem

I'm running into an odd issue with a Backbone.js Model where an array member is being shown as blank. It looks something like this: ``` var Session = Backbone.Model.extend({ defaults: { // ... widgets: [] }, addWidget: function (widget) { var widgets = this.get("widgets"); widgets.push(widget); this.trigger("change:widgets", this, widgets); }, // ... // I have a method on the model to grabbing a member of the array getWidget: function (id) { console.log(this.attributes); console.log(this.attributes.widgets); // ... } }); ``` I then add a widget via `addWidget`. When trying `getWidget` the result I get (in Chrome) is this: ``` Object widgets: Array[1] 0: child length: 1 __proto__: Array[0] __proto__: Object [] ``` It's showing that widgets is not empty when logging `this.attributes` but it's shown as empty when logging `this.attributes.widgets`. Does anyone know what would cause this? EDIT I've changed the model to instantiate the widgets array in the initialization method to avoid references across multiple instances, and I started using backbone-nested with no luck.

Original source