-1

I have a question related to contained backbonejs model objects. Using yeoman backbone generator described at https://github.com/yeoman/generator-backbone, I created a backbone application to test how a model object that contains another model object is being sent as json to the backend server.

I added two models contact and address to this test application.

yo backbone:model contact

yo backbone:model address

Contact object contains one address object. Contact and address backbone model objects are shown below. The init function in the generated main.js is also shown below. The console log is shown below. Ignore the POST error since there is no endpoint contacts.

My question is: in the Chrome browser Developer Tools window, network tab the request payload is:

{"name":"John Doe"}

What changes are needed to the backbone model objects so that the request payload will have the contained address object also? Thanks. I want the payload to look like this:

    {
    "name": "John Doe",
    "address": {
        "addressLine1": "Somewhere"
    }
}

From console in the Developer Tools window, I can confirm addressLine1 is 'Somewhere' in the contained address object :

    Inside Contact.initialize
address.js:14 Inside Address.initialize
contact.js:24 Inside Contact.getAddress
main.js:12 Hello from Backbone! name = John Doe addressLine1 = Somewhere
contact.js:21 Inside Contact.validate
main.js:22 return value from save [object Object]
jquery.js:8630 POST http://localhost:9001/contacts 404 (Not Found)
...
main.js:19 Error [object Object]

From main.js

 init: function () {
'use strict';
var myContact = new Test.Models.Contact();
console.log('Hello from Backbone! name = ' + myContact.get('name') + ' addressLine1 = ' + myContact.getAddress().get('addressLine1'));

var rv = myContact.save(null,{
                    success: function(response) {
                        console.log('Success ' + response);
                    },
                    error: function(response) {
                        console.log('Error ' + response);
                    }
                });
console.log ('return value from save ' + rv);

} };

From contact.js

    /*global Test, Backbone*/
Test.Models = Test.Models || {};

(function () {
  'use strict';

  Test.Models.Contact = Backbone.Model.extend({

    url: '/contacts',

    initialize: function() {
        console.log ('Inside Contact.initialize');
        this.address=new Test.Models.Address();
    },

    defaults: {
        name: 'John Doe'
    },

    validate: function(attrs, options) {
        console.log ('Inside Contact.validate');
    },
    getAddress: function() {
        console.log ('Inside Contact.getAddress');
        return this.address;
    },
    parse: function(response, options)  {
        console.log ('Inside Contact.parse');
      return response;
    }
  });

})();

From address.js

    /*global Test, Backbone*/

Test = {}; // a global object 
Test.Models = Test.Models || {};

(function () {
  'use strict';

  Test.Models.Address = Backbone.Model.extend({

    url: '',

    initialize: function() {
        console.log ('Inside Address.initialize');
    },

    defaults: {
        addressLine1: 'Somewhere'
    },

    validate: function(attrs, options) {
        console.log ('Inside Address.validate');
    },

    parse: function(response, options)  {
        console.log ('Inside Address.parse');
      return response;
    }
  });

})();

Call stack when I set a breakpoint at contact validate function:

    validate (contact.js:21)
_validate (backbone.js:568)
save (backbone.js:465)
init (main.js:14)
(anonymous) (main.js:29)
fire (jquery.js:3099)
fireWith (jquery.js:3211)
ready (jquery.js:3417)
completed (jquery.js:3433)

When the above break point is triggered, I can verify this object has address information:

    this
child {cid: "c1", attributes: {…}, _changing: false, _previousAttributes: {…}, changed: {…}, …}
address:child
attributes:{addressLine1: "Somewhere"}
changed:{}
cid:"c2"
_changing:false
_pending:false
_previousAttributes:{}
__proto__:Backbone.Model
attributes:{name: "John Doe"}
changed:{}
cid:"c1"
_changing:false
_pending:false
_previousAttributes:{}
__proto__:Backbone.Model

Thanks a lot.

Ganesh
  • 44
  • 1
  • 6
  • 1. [Nesting collection or models within another model](https://stackoverflow.com/a/40823148/1218980), 2. [Set nested attributes](https://stackoverflow.com/a/41701463/1218980), 3. [bubbling events of nested models and collections](https://stackoverflow.com/a/40532592/1218980) – Emile Bergeron Dec 22 '17 at 21:10

1 Answers1

0

I saw Nesting collection or models within another model

I added the following line of code just before I save the model in main.js:

myContact.set('address', myContact.getAddress().toJSON());

then I can verify the request payload is what I was expecting:

{"name":"John Doe","address":{"addressLine1":"Somewhere"}}

Thanks to Emile Bergeron for pointing out toJSON() method must be called.

The take away for me is backbone is bare bones. It is not smart enough to figure out an object may contain other objects and do the needful. The javascript programmer must call toJSON() at appropriate time.

Emile Bergeron
  • 17,074
  • 5
  • 83
  • 129
Ganesh
  • 44
  • 1
  • 6
  • Backbone is smart enough and it shouldn't figure out itself that you're nesting models as **it's not Backbone's job, it's yours.** The logic is from you, **you have to** figure out when to call `toJSON` to get the model's `attributes` hash **when you need it.** – Emile Bergeron Dec 27 '17 at 06:08