How to get nested object's attributes from model.toJSON - backbone.js

I am learning Backbone.js. I have a model call myModel, and here is the console.log result when I call myModel.toJSON():
Object {accountId: "523f628e80d52a2805000004", added: "2013-09-26T06:26:12.765Z", updated: "2013-09-26T06:26:12.765Z", _id: "5243d384951b6cef05000004", name: Object}
I want to get the attributes in name, when I console.log myModel.toJSON().name, I got this result:
Object {first: "myfirst", last: "mylast"}
Everything works fine, until I call myModel.toJSON().name.first, I got a console error says
Cannot read property 'first' of undefined
I thought myModel.toJSON().name is an object, and to get the 'first' attribute from it, I just need to do myModel.toJSON().name.first. Any thought why it doesn't work?
This is the entire model I have:
r {cid: "c71", attributes: Object, collection: r, _changing: false, _previousAttributes: Object…}
_changing: false
_events: Object
_pending: false
_previousAttributes: Object
attributes: Object
_id: "5243d384951b6cef05000004"
accountId: "523f628e80d52a2805000004"
added: "2013-09-26T06:26:12.765Z"
name: Object
first: "myfirst"
last: "mylast"
__proto__: Object
updated: "2013-09-26T06:26:12.765Z"
__proto__: Object
changed: Object
cid: "c71"
collection: r
__proto__: s

Related

jest shallow render find by class excluding

I am testing a class like:
const wrapper = shallow(<Features {...props}/>);
expect(wrapper.find('.Feature__Item:not(.Feature__Showmore)').length).toBe(2);
But, I am getting an error like this:
Error: Enzyme::Selector does not support pseudo-element or pseudo-class selectors.
How can I work around this limitation?
Update: Interesting observation, when I wrote the following in the debug console: wrapper.find('.Feature__Item').findWhere(a => a.hasClass('Feature__Showmore') === false).length
The output was:
0:Object {nodeType: "host", type: "li", props: Object, …}
1:Object {nodeType: "function", type: , props: Object, …}
2:Object {nodeType: "host", type: "li", props: Object, …}
3:Object {nodeType: "function", type: , props: Object, …}
I found another way which did the trick:
expect(wrapper.find('.Feature__Item').not('.Feature__Showmore').length).toBe(2);
You could try with findWhere:
expect(wrapper.find('.Feature__Item').findWhere(a => a.hasClass('Feature__Showmore') === false).length).toBe(2);
This will first get all the elements having class Feature__Item and then exclude from this list the ones which don't have Feature__Showmore class.

Converting localStorage to Parse.com

As an exercise to myself for a future app, I'm attempting to convert a modified app from a book that uses localStorage. The converted app will use Parse.com data instead of localStorage.
Long story short, it's not working. I can fetch the collection from Parse.com, but the View won't render it. I don't get any errors, it just does not display the data. After a lot of debugging, I noticed a difference between the array that is returned in the localStorage version and the Parse.com version:
localStorage:
Array[1]
0: child
[object Object]: (...)
get [object Object]: function () {
set [object Object]: function (newval) {
[object Object],[object Object]: (...)
get [object Object],[object Object]: function () {
set [object Object],[object Object]: function (newval) {
[object Object],[object Object],[object Object]: (...)
get [object Object],[object Object],[object Object]: function () {
set [object Object],[object Object],[object Object]: function (newval) {
__backboneDebugger__appComponentInfo: window.__backboneAgent.AppComponentInfo
__backboneDebugger__isInstancePatched: true
_byId: Object
_events: Object
initialize: (...)
length: 3
models: (...)
get models: function () {
set models: function (newval) {
sync: function () {
trigger: function (name) {
url: (...)
get url: function () {
set url: function (newval) {
watchers: Object
__proto__: Surrogate
length: 1
__proto__
but Parse.com version:
Array[1]
0: child
_byCid: Object
_byId: Object
_callbacks: Object
length: 2
models: Array[2]
0: child
_callbacks: Object
_escapedAttributes: Object
_hasData: true
_hashedJSON: Object
_opSetQueue: Array[1]
_pending: Object
_previousAttributes: Object
_serverData: Object
_silent: Object
attributes: Object
changed: Object
cid: "c1"
collection: child
createdAt: Wed Apr 16 2014 20:23:50 GMT-0400 (EDT)
id: "qYM3ORQ6po"
updatedAt: Fri Apr 18 2014 18:21:12 GMT-0400 (EDT)
__proto__: EmptyConstructor
1: child
_callbacks: Object
_escapedAttributes: Object
_hasData: true
_hashedJSON: Object
_opSetQueue: Array[1]
_pending: Object
_previousAttributes: Object
_serverData: Object
_silent: Object
attributes: Object
changed: Object
cid: "c2"
collection: child
createdAt: Wed Apr 16 2014 22:10:07 GMT-0400 (EDT)
id: "SpCYqDPZdZ"
updatedAt: Wed Apr 16 2014 22:27:16 GMT-0400 (EDT)
__proto__: EmptyConstructor
length: 2
__proto__: Array[0]
__proto__: EmptyConstructor
length: 1
localStorage renders properly, but Parse.com doesn't render at all. The correct data is in the Parse.com array... so it's certainly retrieving it from Parse.com. But, as you can see, the data is formatted very differently.
I suspect that's where my problem lies.
The main difference between the code is "Backbone.model" was changed to "Parse.Object"... and "Backbone.Collection" changed to "Parse.Collection". I then removed the "url" parameter from the Parse.Collection and specified the model:
localStorage
Entities.CharacterCollection = Backbone.Collection.extend({
url: "characters",
model: Entities.Character
});
Parse.com:
Entities.CharacterCollection = Parse.Collection.extend({
model: Entities.Character
});
I am really at a loss here. I have the feeling the problem is simple, but I'm just missing it.
I'm using the Parse.com JavaScript API, and my code using Marionette as well.
Thank you very much in advance!
I'm not familiar with parse.com but aren't you able to retrieve the data from parse.com and stucture it as such that you can use it to fill a backbone.collection?

Backbone+Parse.com Collection.fetch() returns empty array using event callback

i'm starting using parse.com to develop a web app but i'm stuck on a simple problem.
I defined a model (or object in Parse SDK) as:
Book.Model = Parse.Object.extend("book", {
// Default attributes for the book.
defaults: {
title: "placeholder...",
},
// Ensure that each book created has `title`.
initialize: function() {
if (!this.get("title")) {
this.set({"title": this.defaults.title});
}
},
});
and a collection:
Book.List = Parse.Collection.extend({
// Reference to this collection's model.
model: Book.Model,
initialize: function() {
},
});
Then, if i try something like
var books = new Book.List();
books.fetch({
success: function(collection) {
console.warn(collection);
},
error: function(collection, error) {
// The collection could not be retrieved.
}
});
Everything goes fine. Log:
child {length: 5, models: Array[5], _byId: Object, _byCid: Object, model: function…}
_byCid: Object
_byId: Object
length: 5
models: Array[5]
__proto__: EmptyConstructor
BUT if i try to use event callback instead of success method i get an empty array. Code:
books.on('reset', this.log());
books.fetch();
log: function() {
console.log(books);
}
and log:
child {length: 0, models: Array[0], _byId: Object, _byCid: Object, model: function…}
_byCid: Object
_byId: Object
length: 5
models: Array[5]
__proto__: EmptyConstructor
which is quite strange (because i think that each solution wait for the collection to be populated from the server). Does anybody know why is this happening?
I'm actually using Backbone Boilerplate and Parse.com js SDK.
The Collection#fetch behavior has changed, it used to reset the collection by default but as of 1.0.0 it merges the new models using set:
When the model data returns from the server, it uses set to (intelligently) merge the fetched models, unless you pass {reset: true}, [...]
and set doesn't trigger "reset" events, it triggers other events:
All of the appropriate "add", "remove", and "change" events are fired as this happens.
If you want your fetch to reset the collection then you have to say so:
books.fetch({ reset: true });

model's fetch does not work

Here is body of my model
urlRoot: '/users',
parse: function(response) {
return response.User;
}
Here is what is returned when I type /users/1 in my browser:
{"User":{"id":"1","created":"2013-02-13 09:22:42","modified":"2013-02-13 09:22:42","username":"somesuername","password":"","role":"somerole","token":null,"token_expiration":null}}
So the api works.
When I execute this:
this.model.id = 1;
this.model.fetch({ success: function(user){
console.log(user);
}}); // this.model is instance of my model
I get in console:
d {cid: "c4", attributes: Object, _changing: false, _previousAttributes: Object, changed: Object…}
_changing: false
_pending: false
_previousAttributes: Object
attributes: Object
__proto__: Object
changed: Object
cid: "c4"
id: Array[1]
__proto__: e
So the result was successful by model didn't fetch any data - am I missing something?
Backbone.Model stores the data inside the attributes property. From Backbone documentation:
The attributes property is the internal hash containing the model's state — usually (but not necessarily) a form of the JSON object representing the model data on the server. It's often a straightforward serialization of a row from the database, but it could also be client-side computed state.
Please use set to update the attributes instead of modifying them directly.
Try expanding the attributes node in the console object inspector, and you should see your data.

get not retrieving name attribute from object

From the backbone docs
getmodel.get(attribute)
Get the current value of an attribute from the model. For example: note.get("title")
I seeded some data with a name for each country into a Rails app
Country.create!(name: "Brazil")
Country.create!(name: "France")
Country.create!(name: "Germany")
Country.create!(name: "Spain")
In the console, I created a new collection and fetched the data
countries.fetch();
Object
XHR finished loading: "http://localhost:3000/countries".
Checked the length. Equal to the four countries I created.
countries.length
4
Selected a random one using underscore's shuffle method.
c = countries.shuffle()[0]
The object has a name
Backbone.Model
_changes: Array[2]
_currentAttributes: Object
_events: Object
_hasComputed: false
_previousAttributes: Object
attributes: Object
country: Object
created_at: "2013-01-07T06:09:43Z"
id: 2
name: "France"
updated_at: "2013-01-07T06:09:43Z"
__proto__: Object
__proto__: Object
Tried to get the name attribute from the object several different ways, all without success
c.get('name')
undefined
c.get("name");
undefined
c.get("name")
undefined
Can anyone think what I might be doing wrong?
One thing that I find unusual is that there is a 'country' attribute wrapping the other attributes
attributes: Object
country: Object
created_at: "2013-01-07T06:09:43Z"
id: 2
name: "France"
updated_at: "2013-01-07T06:09:43Z"
I'm not sure why 'country' is wrapping the other data. Is it because I created the seed data with a Country model?
Country.create!(name: "Brazil")
anyways, obj.get('country') doesn't return undefined
c = countries.shuffle()[0]
k = c.get('country')
Object
created_at: "2013-01-07T06:09:43Z"
id: 3
name: "Germany"
updated_at: "2013-01-07T06:09:43Z"
__proto__: Object
but I can't do a get on the name after that (i.e after I did the get on country)
k = c.get('country')
Object
k.get('name')
undefined
Is there a way to remove the country wrapper and just be able to do get on the attributes that it was created with?
Override model.parse to extract the country element. Backbone calls parse before populating the model from fetched data:
var Country = Backbone.Model.extend({
parse: function(attributes) {
return attributes.country;
}
});

Resources