Looks like we can't reproduce the issue or there's a problem in the test case provided.
  1. #1
    Sencha User
    Join Date
    Mar 2010
    Posts
    51
    Vote Rating
    2
    koblass is on a distinguished road

      1  

    Default getAssociatedData in Model return also the field tagged as non persistent

    getAssociatedData in Model return also the field tagged as non persistent


    Hi,

    I'm using the getAssociatedData method in order to save my nested data.
    In order to do so I've overwritten the getRecordData method of my Writer like this :

    Code:
     getRecordData: function(record) {
            record.set(record.getAssociatedData());
            return Ext.data.writer.Json.prototype.getRecordData(record);
        }
    Everything works fine, except that the field defined as non persistent (persist:false) are also returned by the getAssociatedData method.

    I think this shouldn't be the case.

    What do you think ?

    Best regards
    Daniel

  2. #2
    Sencha - Senior Forum Manager mitchellsimoens's Avatar
    Join Date
    Mar 2007
    Location
    Gainesville, FL
    Posts
    37,647
    Vote Rating
    899
    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


    persist will only exclude that field from the modified fields so if you do getAssociatedData, there is nothing that will stop it from returning the field.
    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.

  3. #3
    Sencha User
    Join Date
    Apr 2012
    Posts
    2
    Vote Rating
    1
    ZIOLele is on a distinguished road

      1  

    Default


    This is an override wich implements the requested feature it surely can be done better, but this works, i've checked that :-D. Also this is for 4.1.

    Hope it helps.

    P.S.: Al code is standard extjs or copied from this forum, i've just added some little pieces here and there.


    Code:
    Ext.define('Zll.data.model.GetDataPatch',{
        override:'Ext.data.Model',
        getData: function(includeAssociated,excludeNotPersisted){
            var me     = this,
            fields = me.fields.items,
            fLen   = fields.length,
            data   = {},
            name, f, persistent;
            
            persistent = (excludeNotPersisted == undefined)?false:excludeNotPersisted;
                
            for (f = 0; f < fLen; f++) {
                if (!persistent)
                {
                    name = fields[f].name;
                    data[name] = me.get(name);            
                }
                else
                {
                    if(fields[f].persist)
                    {
                        console.log('prova');
                        name = fields[f].name;
                        data[name] = me.get(name);                                
                    }
                }
            }
        
            if (includeAssociated === true) {
                Ext.apply(data, me.getAssociatedData());
            }
            return data;
        },
        
        getAssociatedData: function(persistedFields){
            return this.prepareAssociatedData({}, 1,persistedFields);
        },
    
        /**
         * @private
         * This complex-looking method takes a given Model instance and returns an object containing all data from
         * all of that Model's *loaded* associations. See {@link #getAssociatedData}
         * @param {Object} seenKeys A hash of all the associations we've already seen
         * @param {Number} depth The current depth
         * @return {Object} The nested data set for the Model's loaded associations
         */
        prepareAssociatedData: function(seenKeys, depth,persistedFields) {
            /**
             * In this method we use a breadth first strategy instead of depth
             * first. The reason for doing so is that it prevents messy & difficult
             * issues when figuring out which associations we've already processed
             * & at what depths.
             */
            var me               = this,
                associations     = me.associations.items,
                associationCount = associations.length,
                associationData  = {},
                // We keep 3 lists at the same index instead of using an array of objects.
                // The reasoning behind this is that this method gets called a lot
                // So we want to minimize the amount of objects we create for GC.
                toRead           = [],
                toReadKey        = [],
                toReadIndex      = [],
                associatedStore, associatedRecords, associatedRecord, o, index, result, seenDepth,
                associationId, associatedRecordCount, association, i, j, type, name;
    
            for (i = 0; i < associationCount; i++) {
                association = associations[i];
                associationId = association.associationId;
                
                seenDepth = seenKeys[associationId];
                if (seenDepth && seenDepth !== depth) {
                    continue;
                }
                seenKeys[associationId] = depth;
    
                type = association.type;
                name = association.name;
                if (type == 'hasMany') {
                    //this is the hasMany store filled with the associated data
                    associatedStore = me[association.storeName];
    
                    //we will use this to contain each associated record's data
                    associationData[name] = [];
    
                    //if it's loaded, put it into the association data
                    if (associatedStore && associatedStore.getCount() > 0) {
                        associatedRecords = associatedStore.data.items;
                        associatedRecordCount = associatedRecords.length;
    
                        //now we're finally iterating over the records in the association. Get
                        // all the records so we can process them
                        for (j = 0; j < associatedRecordCount; j++) {
                            associatedRecord = associatedRecords[j];
                            associationData[name][j] = associatedRecord.getData(false,persistedFields);
                            toRead.push(associatedRecord);
                            toReadKey.push(name);
                            toReadIndex.push(j);
                        }
                    }
                } else if (type == 'belongsTo' || type == 'hasOne') {
                    associatedRecord = me[association.instanceName];
                    // If we have a record, put it onto our list
                    if (associatedRecord !== undefined) {
                        associationData[name] = associatedRecord.getData(false,persistedFields);
                        toRead.push(associatedRecord);
                        toReadKey.push(name);
                        toReadIndex.push(-1);
                    }
                }
            }
            
            for (i = 0, associatedRecordCount = toRead.length; i < associatedRecordCount; ++i) {
                associatedRecord = toRead[i];
                o = associationData[toReadKey[i]];
                index = toReadIndex[i];
                result = associatedRecord.prepareAssociatedData(seenKeys, depth + 1);
                if (index === -1) {
                    Ext.apply(o, result);
                } else {
                    Ext.apply(o[index], result);
                }
            }
    
            return associationData;
        }
    });
    
    
    Ext.define('Zll.data.writer.DeepJson', {
        extend : 'Ext.data.writer.Json',
        alternateClassName : 'Ext.data.DeepJsonWriter',
        alias : 'writer.deepjson',
        getRecordData : function(record) {
            var data = this.callParent(arguments);
    
            var associated = record.getAssociatedData(true);
            for (name in associated) {
                console.log(name);
                console.log(associated[name]);
                data[name] = associated[name];
            }
            return data;
        }
    });
    To use it you just need to declare the writer as a DeepJson:

    Code:
    ....
            writer: Ext.create('Zll.data.writer.DeepJson',{
                allowSingle: false,
                writeAllFields: true
            })
    ....
    Last edited by ZIOLele; 4 May 2012 at 4:20 AM. Reason: Added example of use

  4. #4
    Sencha User VDP's Avatar
    Join Date
    Feb 2012
    Location
    Boom, Belgium
    Posts
    87
    Vote Rating
    10
    VDP will become famous soon enough

      0  

    Default


    Quote Originally Posted by mitchellsimoens View Post
    persist will only exclude that field from the modified fields so if you do getAssociatedData, there is nothing that will stop it from returning the field.
    Nice fun-fact. This might not be a bug but rather a feature request.

    I get it that you should be able to get all data but shouldn't you be able to get all data that needs to be persisted too? A field marked as persistent: false is expected not to be included.

    I like ZIOLele 's override. Thank you very much!