-
14 Jun 2012 7:11 PM #1
Problem with localstorage store and model with hasMany association
Problem with localstorage store and model with hasMany association
Is store with 'localstorage' proxy is support a models with hasMany associations?
I have a model with one hasMany association:my store with localstorage proxy:Code:Ext.define('Cart', { extend: 'Ext.data.Model', config: { fields: [ {name: 'id', type: 'string'}, {name: 'created', type: 'date'} {name: 'status', type: 'boolean'} ], idProperty: 'id', identifier: { type: 'uuid' }, associations: [ { type: 'hasMany', model: 'Product', associationKey: 'products', foreignKey: 'cart_id', name: 'products', autoLoad: true } ] } }); Ext.define('Product', { extend: 'Ext.data.Model', config: { fields: [ {name: 'product_id', type: 'string'}, {name: 'quantity', type: 'integer'}, {name: 'cart_id', type: 'string'}, ], idProperty: 'product_id', belongsTo: 'Cart' } });I tried to add record to store:Code:Ext.define('Cartstore', { extend: 'Ext.data.Store', config: { model: 'Cart', proxy: { type: 'localstorage', id: 'carts' } } });After that I see in localstorage first model data only without associated data.Code:var newCart = Ext.create('Cart', { 'created': new Date(), 'status': true }); newCart.products().add(Ext.create('Product', { 'product_id': 10, 'quantity': 1 })); Ext.getStore('Cartstore').add(newCart).sync();
No errors in console. But no associated data in localstorage.
Where I am wrong?
-
15 Jun 2012 12:18 AM #2
I think you should define a localstorage for your products and use the foreign key to select the right products when loading. I think the reason for you problem is found in the documentation, since localstorage says:
You might also have luck in configuring the store and/or writer, but I think having them in separate stores will be better. I've been programming with nested stores since yesterday (due to nested data in my JSON service) and I have to say I don't think it's pretty compared to normal store setup.HTML5 localStorage is a key-value store (e.g. cannot save complex objects like JSON), so LocalStorageProxy automatically serializes and deserializes data when saving and retrieving it.Developer/Alien Technologies at Mobile Ambitions Aps, Denmark.
-
15 Jun 2012 6:21 AM #3
Make two separate stores for a cart and products - it's a good idea.
But I do not see any barriers for the storage of models with hasMany association because data is stored as single JSON-string.
Most likely this is error in localstorage proxy... or this proxy simply not support hasMany associations.
If so - then let the developers will confirm this.
-
15 Jun 2012 9:55 AM #4
I don't know if you have seen it, but this seems to answer your question: http://www.sencha.com/forum/showthre...l=1#post762500
Developer/Alien Technologies at Mobile Ambitions Aps, Denmark.
-
17 Jun 2012 9:34 AM #5Sencha - Senior Forum Manager
- Join Date
- Mar 2007
- Location
- St. Louis, MO
- Posts
- 33,714
- Vote Rating
- 438
Mitchell Simoens @SenchaMitch
Sencha Inc, Senior Forum Manager
________________
http://www.JSONPLint.com - Source to lint your JSONP!
Check out my GitHub, lots of nice things for Ext JS 4 and Sencha Touch 2
https://github.com/mitchellsimoens
Think my support is good? Get more personalized support via a support subscription. https://www.sencha.com/store/
Need more help with your app? Hire Sencha Services services@sencha.com
Want to learn Sencha Touch 2? Check out Sencha Touch in Action that is almost in print!
When posting code, please use BBCode's CODE tags.
-
17 Jun 2012 2:39 PM #6
for now my problem was fixed by adding a store configuration into hasMany association config (http://docs.sencha.com/touch/2-0/#!/...ny-cfg-store):
and what is the result? I can store and read stored data with hasMany association.Code:associations: [ { type: 'hasMany', model: 'Product', associationKey: 'products', foreignKey: 'cart_id', name: 'products', autoLoad: true, store: { model: 'Product', proxy: { type: 'localstorage', id: 'products' } } } ]
As it turned, all included
I have not yet quite completely done tests about possibility of working with hasMany data. If I have any problems - I'll write here.
-
20 Jun 2012 12:49 PM #7
I took kostysh's ideas and made it almost work. The problem is that the products store is acting global, so anytime you add a new cart, all products previously saved are now associated with the NEW cart, not the old ones that they were added to. I need multiple carts and each cart to have its own separate list of products. Is that even possible?
For an app that ONLY needs one cart, this would work, but I am just using this as a proof of concept before I apply my more complex data - where I need a main list of items, each with its own list of associated items.
This code plus the sencha include is all you need to test
Code:<!DOCTYPE html> <html> <head> <title>Contacts</title> <link href="lib/touch/resources/css-debug/sencha-touch.css" rel="stylesheet" type="text/css" /> <script type="text/javascript" src="lib/touch/sencha-touch-all-debug.js"></script> <script type="text/javascript"> Ext.define('Cart', { extend: 'Ext.data.Model', config: { fields: [ {name: 'id', type: 'string'}, {name: 'created', type: 'date'}, {name: 'status', type: 'boolean'} ], idProperty: 'id', identifier: { type: 'uuid' }, associations: [ { type: 'hasMany', model: 'Product', associationKey: 'products', foreignKey: 'cart_id', name: 'products', autoLoad: true, store: { model: 'Product', proxy: { type: 'localstorage', id: 'products' } } } ] } }); Ext.define('Product', { extend: 'Ext.data.Model', config: { fields: [ {name: 'product_id', type: 'string'}, {name: 'quantity', type: 'integer'}, {name: 'cart_id', type: 'string'}, ], // DONT SET OR DIFFERENT CARTS CANT HAVE THE SAME PRODUCT ID's //idProperty: 'product_id', identifier: { type: 'uuid' }, belongsTo: 'Cart' } }); Ext.define('Cartstore', { extend: 'Ext.data.Store', config: { model: 'Cart', proxy: { type: 'localstorage', id: 'carts' } } }); Ext.application({ name: 'app', launch: function() { // create the store cart = Ext.create('Cartstore'); // load saved data from localstorage cart.load(); // manually load associated products for each cart from localstorage cart.each(function(record){ record.products().load(); }); // you can see the full object with all related data is in there console.log(cart); // create a new cart var newCart = Ext.create('Cart', { 'created': new Date(), 'status': true }); // PROBLEM: this new cart has ALL existing products put into it automatically.... console.log(newCart.products()); // add some products newCart.products().add(Ext.create('Product', { 'product_id': 10, 'quantity': 1 })); newCart.products().add(Ext.create('Product', { 'product_id': 25, 'quantity': 3 })); // this contains the new cart with all the existing products, and all the new products console.log(newCart); // add the new cart to the store cart.add(newCart); // save cart to local storage cart.sync(); // manually save the products to localstorage newCart.products().sync(); // store will have old and newly added carts but newest cart will have all products associated with it console.log(cart); } }); </script> </head> <body> </body> </html>
-
20 Jun 2012 4:03 PM #8
When creating a new item (cart), internally it is calling load, and then read (when newCart.products() is first called). The read function is sent a filter with the new items uuid, but that filter is not applied, and instead all records are UPDATED to use the new uuid, instead of filtered to match the new uuid.
I changed my Ext.data.proxy.WebStorage.read() in the sencha 2 library to be:
Code:read: function(operation, callback, scope) { var records = [], ids = this.getIds(), model = this.getModel(), idProperty = model.getIdProperty(), params = operation.getParams() || {}, length = ids.length, i, record, filters, tmpRecords = []; filters = operation.getFilters() || []; //read a single record if (params[idProperty] !== undefined) { record = this.getRecord(params[idProperty]); if (record) { tmpRecords.push(record); //operation.setSuccessful(); } } else { for (i = 0; i < length; i++) { tmpRecords.push(this.getRecord(ids[i])); //operation.setSuccessful(); } } // remove items that dont match filter if(filters.length > 0) { for(i = 0; i < tmpRecords.length; i++) { var add = true; for(var x = 0; x < filters.length; x++) { if(tmpRecords[i].data[filters[x]._property] != filters[x]._value) { add = false; } } if(add) { records.push(tmpRecords[i]); } } } else { records = tmpRecords; } if(records.length > 0) { operation.setSuccessful(); } operation.setCompleted(); operation.setResultSet(Ext.create('Ext.data.ResultSet', { records: records, total : records.length, loaded : true })); operation.setRecords(records); if (typeof callback == 'function') { callback.call(scope || this, operation); } }
And it works! Loading the data, and adding new data! I have not yet tested adding new products to an existing cart. I will do that next.
-
20 Jun 2012 4:09 PM #9
Adding new products to existing cart works totally fine too
Code:// add new products to existing cart existingCart = cart.data.items[0]; existingCart.products().add(Ext.create('Product', { 'product_id': 99, 'quantity': 100 })); existingCart.products().sync();
-
21 Jun 2012 3:03 PM #10
Janelle, you totally rock. Your override works wonderfully. Thank you!


Reply With Quote