browse by category or date

This is the continuation of my previous post. On that post I found that the exception was thrown on this line:

store = Ext.create('Ext.data.Store', {
	storeId: 'modelStore',
	model: 'mdl'
});

By logging the exception into console, we can see the stack trace:

So I put a breakpoint inside functionFactory and clicked the “Load to Grid” button again. From there, I can see functionFactory throws error because of the strings it received from its caller.

Its caller was buildRecordDataExtractor:

buildRecordDataExtractor: function() {
    var c = this,
        a = c.model.prototype,
        b = {
            clientIdProp: a.clientIdProperty,
            fields: a.fields.items
        };
    c.recordDataExtractorTemplate.createFieldAccessExpression = function() {
        return c.createFieldAccessExpression.apply(c, arguments)
    };
    return Ext.functionFactory(c.recordDataExtractorTemplate.apply(b)).call(c)
}

From there we can see that the string template is declared inside recordDataExtractorTemplate:

recordDataExtractorTemplate: [
        "var me = this\n", 
        "    ,fields = me.model.prototype.fields\n", 
        "    ,value\n", 
        "    ,internalId\n", 
        '<tpl for="fields">', 
        '    ,__field{#} = fields.map["{name}"]\n', 
        "</tpl>", 
        ";\n", 
        "return function(dest, source, record) {\n", 
        '<tpl for="fields">', 
        '{% var fieldAccessExpression =  this.createFieldAccessExpression(values, "__field" + xindex, "source");', 
        "   if (fieldAccessExpression) { %}", 
        '    value = {[ this.createFieldAccessExpression(values, "__field" + xindex, "source") ]};\n', 
        '<tpl if="hasCustomConvert">', 
        '    dest["{name}"] = value === undefined ? __field{#}.convert(__field{#}.defaultValue, record) : __field{#}.convert(value, record);\n', 
        '<tpl elseif="defaultValue !== undefined">', 
        "    if (value === undefined) {\n", 
        "        if (me.applyDefaults) {\n", '<tpl if="convert">', 
        '            dest["{name}"] = __field{#}.convert(__field{#}.defaultValue, record);\n', 
        "<tpl else>", 
        '            dest["{name}"] = __field{#}.defaultValue\n', 
        "</tpl>", 
        "        };\n", 
        "    } else {\n", 
        '<tpl if="convert">', 
        '        dest["{name}"] = __field{#}.convert(value, record);\n', 
        "<tpl else>", 
        '        dest["{name}"] = value;\n', 
        "</tpl>", 
        "    };\n", 
        "<tpl else>", 
        "    if (value !== undefined) {\n", 
        '<tpl if="convert">', 
        '        dest["{name}"] = __field{#}.convert(value, record);\n', 
        "<tpl else>", 
        '        dest["{name}"] = value;\n', 
        "</tpl>", 
        "    }\n", 
        "</tpl>", 
        "{% } else { %}", 
        '<tpl if="defaultValue !== undefined">', 
        '<tpl if="convert">', 
        '    dest["{name}"] = __field{#}.convert(__field{#}.defaultValue, record);\n', 
        "<tpl else>", 
        '    dest["{name}"] = __field{#}.defaultValue\n', 
        "</tpl>", "</tpl>", "{% } %}", "</tpl>", 
        '<tpl if="clientIdProp">', 
        '    if (record && (internalId = {[ this.createFieldAccessExpression({mapping: values.clientIdProp}, null, "source") ]})) {\n', 
        '        record.{["internalId"]} = internalId;\n', 
        "    }\n", 
        "</tpl>", 
        "};"
    ]

By observing the string array template above and comparing it with the generated string, we can find that method createFieldAccessExpression is responsible for generating portion of the string which throws exception.

createFieldAccessExpression: (function() {
    var a = /[\[\.]/;
    return function(o, d, e) {
        var b = o.mapping,
            m = b || b === 0,
            c = m ? b : o.name,
            p, g;
        if (b === false) {
            return
        }
        if (typeof c === "function") {
            p = d + ".mapping(" + e + ", this)"
        } else {
            
            if (this.useSimpleAccessors === true || ((g = String(c).search(a)) < 0)) {
                if (!m || isNaN(c)) {
                    c = '"' + c + '"'
                }
                p = e + "[" + c + "]"
            } else {
                if (g === 0) {
                    p = e + c
                } else {
                    var j = c.split("."),
                        l = j.length,
                        k = 1,
                        n = e + "." + j[0],
                        h = [n];
                    for (; k < l; k++) {                            
                        n += "." + j[k];
                        h.push(n)
                    }
                    p = h.join(" && ")
                }
            }
        }
        return p
    }
}())

In order to access the property using array index, we must add our condition into this line:

if (this.useSimpleAccessors === true || ((g = String(c).search(a)) < 0)) {
   // ... SNIP ...
}

After a few tries, here's the code that solved it:

g = String(c).search(a);
h = String(c).indexOf(".");
while (h>0 && !i) {
    i = parseInt(c[h+1])>=0;
    h = String(c).indexOf(".", h+1);                    
}
if (this.useSimpleAccessors === true || g < 0 || i) {
   // ... SNIP ...
}

Now it works!

I hope it helps!

GD Star Rating
loading...
Debugging Sencha Ext.JS 4.2.1 Ext.data.Store creation, 4.0 out of 5 based on 1 rating

About Hardono

Hi, I'm Hardono. I am working as a Software Developer. I am working mostly in Windows, dealing with .NET, conversing in C#. But I know a bit of Linux, mainly because I need to keep this blog operational. I've been working in Logistics/Transport industry for more than 11 years.

No Comment

Add Your Comment