+ Start a Discussion
Dominic BlytheDominic Blythe 

SmartSync SObject created in offline mode has no attributes - MobileSDK 2.1 hybrid iOS

I'm building an iOS hybrid mobile app by altering the AccountEditor example, using MobileSDK 2.1. It's going quite well but I've hit something odd. The sample apps have an online/offline indicator and SmartSync handles this nicely, going to the local copies of records when there's no connection and querying the server when connected. It offers to sync locally modified records when it comes back online. All very nice.

My problem is that I'm also creating records. When I create a record offline, and then go and view it offline, that specific record is returned from the query with no result.attributes while the records that were created online do have result.attributes, even when viewed offline. I have peppered the standard js with console.log(...) to find out what's going on.

Here are some excerpts:

Dumping out all the properties of result (cache query result) entry for the record added offline. Note no "attributes" property. The records created online DO have an "attributes" property.
2014-01-06 18:07:26.848 Mobile_Dev01_b[3515:70b] [LOG] 1514 _soupEntryId:7
2014-01-06 18:07:26.848 Mobile_Dev01_b[3515:70b] [LOG] 1514 Meeting__c:a0qM0000001PCduIAG
2014-01-06 18:07:26.848 Mobile_Dev01_b[3515:70b] [LOG] 1514 Id:local_1389031510806592
2014-01-06 18:07:26.848 Mobile_Dev01_b[3515:70b] [LOG] 1514 __locally_created__:true
2014-01-06 18:07:26.849 Mobile_Dev01_b[3515:70b] [LOG] 1514 type:Portfolio_Meeting__c
2014-01-06 18:07:26.849 Mobile_Dev01_b[3515:70b] [LOG] 1514 __locally_updated__:false
2014-01-06 18:07:26.849 Mobile_Dev01_b[3515:70b] [LOG] 1514 Client_Portfolio__r:[object Object]
2014-01-06 18:07:26.849 Mobile_Dev01_b[3515:70b] [LOG] 1514 __local__:true
2014-01-06 18:07:26.849 Mobile_Dev01_b[3515:70b] [LOG] 1514 _soupLastModifiedDate:1389031510814
2014-01-06 18:07:26.849 Mobile_Dev01_b[3515:70b] [LOG] 1514 Client_Portfolio__c:a0DM00000085zYyMAI
2014-01-06 18:07:26.849 Mobile_Dev01_b[3515:70b] [LOG] 1514 __locally_deleted__:false
2014-01-06 18:07:26.850 Mobile_Dev01_b[3515:70b] [LOG] 1514 Interest_Level__c:High

The error that causes the Success Callback to fail - smartsync.js Force.SObjectCollection parse method is trying to parse the result but can't:
 
2014-01-06 18:07:26.850 Mobile_Dev01_b[3515:70b] [LOG] 'undefined' is not an object (evaluating 'result.attributes.type') -[object Arguments]-

Anyone have any ideas?
juhanajuhana
Do you set any attribute ?

For example I am creating Event and setting attribute for it:

var event = new Event({Id:null, attributes:{type:"Event"}});

Dominic BlytheDominic Blythe
I'm doing what the backbone.js documentation says to do, which is instead of setting attributes directly, use the set() method:

http://backbonejs.org/#Model-attributes
Please use set to update the attributes instead of modifying them directly. If you'd like to retrieve and munge a copy of the model's attributes, use _.clone(model.attributes) instead.

here's my code:
pm = new app.models.Portfolio_Meeting__c();
                        pm.set("type",pm.sobjectType)
                        pm.set("Meeting__c",id);
                        pm.set("Interest_Level__c","High");
                        pm.set("Client_Portfolio__c", cModels[ix].get("Id"));
                       
                        pm.set("Client_Portfolio__r",
                                {"Name": cModels[ix].get("Name"),
                                 "Scheme_Name__c": cModels[ix].get("Scheme_Name__c"),
                                 "Market_Value_GBP__c": cModels[ix].get("Market_Value_GBP__c"),
                                 "Market_Value_Base_Currency__c": cModels[ix].get("Market_Value_Base_Currency__c"),
                                 "Base_Currency__c": cModels[ix].get("Base_Currency__c")
                               }
                        );



But this seems to be setting these values directly into the object as eg pm.type rather than as pm.attributes.type

The weird thing is, this is working, except for reading the object back when I'm offline. And then only the created-offline object has a problem. All the other instances (created online, or previously synced) have an attributes property with only 2 properties of its own:
2014-01-06 18:07:26.848 Mobile_Dev01_b[3515:70b] [LOG] 1515 url:/services/data/v28.0/sobjects/Portfolio_Meeting__c/a0tM0000001RYcCIAW
2014-01-06 18:07:26.848 Mobile_Dev01_b[3515:70b] [LOG] 1515 type:Portfolio_Meeting__c



Dominic BlytheDominic Blythe
hmm can't find the edit button. I accidentally posted before finishing... The OK objects don't have all the data in their attributes, they only have "type" and "url".
juhanajuhana
Note that you set "type" on root level while type is child of "attributes" what you didn't set.

Try this:

pm.set("attributes",{type:pm.sobjectType});

or set it in constructor like I do with event.
Dominic BlytheDominic Blythe
I understand that the attributes property is a property of the object, so the hierarchy of properties is [thing].attributes.[attribute] but I’m expecting the Backbone documentation to be correct. Not only does it say “do not access the attributes property directly” for set() it says:
juhanajuhana
You want set SObject attributes property, not Backbone model attributes. So, Backbone model contains SObject which means that the SObject attributes are property in Backbone model. Confusing..?

Note that pm.set("attributes",{type:pm.sobjectType}); sets property of attributes to Backbone model. It does not set attributes of Backbone model.

Dominic BlytheDominic Blythe
I was expecting that the Force.SObject object, which is an extension (ultimately) of Backbone.Model should be treated as an instance of a Backbone.Model subclass so that Force.SObject.attributes is the same as Backbone.Model.attributes. Are you saying that Force.SObject.attributes is really a different thing to Backbone.Model.attributes, and so Backbone.Model.set() doesn’t work on it the same?