1. #1
    Sencha User kostysh's Avatar
    Join Date
    Nov 2011
    Location
    Odessa, Ukraine
    Posts
    175
    Vote Rating
    19
    kostysh will become famous soon enough kostysh will become famous soon enough

      0  

    Default 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:
    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'
        }
    });
    my store with localstorage proxy:
    Code:
    Ext.define('Cartstore', {
        extend: 'Ext.data.Store',
        config: {
            model: 'Cart',
            proxy: {
                type: 'localstorage',
                id: 'carts'
            }
        }
    });
    I tried to add record to store:
    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();
    After that I see in localstorage first model data only without associated data.
    No errors in console. But no associated data in localstorage.
    Where I am wrong?

  2. #2
    Sencha User rohdef's Avatar
    Join Date
    Mar 2010
    Location
    Aarhus, Denmark
    Posts
    67
    Vote Rating
    3
    rohdef is on a distinguished road

      0  

    Default


    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:

    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.
    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.
    Developer/Alien Technologies at Mobile Ambitions Aps, Denmark.

  3. #3
    Sencha User kostysh's Avatar
    Join Date
    Nov 2011
    Location
    Odessa, Ukraine
    Posts
    175
    Vote Rating
    19
    kostysh will become famous soon enough kostysh will become famous soon enough

      0  

    Default


    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.

  4. #4
    Sencha User rohdef's Avatar
    Join Date
    Mar 2010
    Location
    Aarhus, Denmark
    Posts
    67
    Vote Rating
    3
    rohdef is on a distinguished road

      0  

    Default


    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.

  5. #5
    Sencha - Senior Forum Manager mitchellsimoens's Avatar
    Join Date
    Mar 2007
    Location
    Gainesville, FL
    Posts
    37,330
    Vote Rating
    847
    mitchellsimoens has a reputation beyond repute mitchellsimoens has a reputation beyond repute mitchellsimoens has a reputation beyond repute mitchellsimoens has a reputation beyond repute mitchellsimoens has a reputation beyond repute mitchellsimoens has a reputation beyond repute mitchellsimoens has a reputation beyond repute mitchellsimoens has a reputation beyond repute mitchellsimoens has a reputation beyond repute mitchellsimoens has a reputation beyond repute mitchellsimoens has a reputation beyond repute

      0  

    Default


    Quote Originally Posted by rohdef View Post
    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
    It's not currently supported but something Tommy is working on how best to do it, it's actually harder than it seems.
    Mitchell Simoens @SenchaMitch
    Sencha Inc, Senior Forum Manager
    ________________
    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 in print!

    When posting code, please use BBCode's CODE tags.

  6. #6
    Sencha User kostysh's Avatar
    Join Date
    Nov 2011
    Location
    Odessa, Ukraine
    Posts
    175
    Vote Rating
    19
    kostysh will become famous soon enough kostysh will become famous soon enough

      2  

    Default


    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):
    Code:
    associations: [            {
                    type: 'hasMany',
                    model: 'Product',
                    associationKey: 'products',
                    foreignKey: 'cart_id',
                    name: 'products',
                    autoLoad: true,
                    store: {
                        model: 'Product',
                        proxy: {
                            type: 'localstorage',
                            id: 'products'
                        }
                    }
                }
            ]
    and what is the result? I can store and read stored data with hasMany association.
    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.

  7. #7
    Sencha User
    Join Date
    Sep 2011
    Posts
    60
    Vote Rating
    3
    janelle is on a distinguished road

      0  

    Default


    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>

  8. #8
    Sencha User
    Join Date
    Sep 2011
    Posts
    60
    Vote Rating
    3
    janelle is on a distinguished road

      0  

    Default


    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.

  9. #9
    Sencha User
    Join Date
    Sep 2011
    Posts
    60
    Vote Rating
    3
    janelle is on a distinguished road

      0  

    Default


    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();

  10. #10
    Ext Premium Member
    Join Date
    Sep 2009
    Posts
    48
    Vote Rating
    1
    yoh.suzuki is on a distinguished road

      0  

    Default


    Janelle, you totally rock. Your override works wonderfully. Thank you!