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...

About Hardono

Howdy! 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.

Possibly relevant:

Alert on scams exploiting this crisis:

[Sent by Gov.sg – 22 Feb]

COVID-19: Be Alert to E-commerce scams

Items like masks and hand sanitisers have been in higher demand.

If you are looking to purchase online:
– Check the credibility of sellers
– Avoid making advance payments
– When in doubt, purchase only from reputable sellers

If you think you’ve been scammed, call the helpline: 1800-722-6688

More: https://www.scamalert.sg/

Update on number of confirmed and discharged cases:

[Sent by Gov.sg]

COVID-19: 22 Feb Update

As of 12pm:
New cases: 3
Total confirmed: 89
Discharged today: 2
Total discharged: 49
Total still in hospital: 40

Most in hospital are stable or improving. 5 are in the intensive care unit.

Of the 3 new cases, 1 is linked to a known cluster and 1 was an evacuee from Wuhan on 9 Feb. Contact tracing is underway for the remaining case.

More: Go.gov.sg/moh22feb

Stay safe everyone!

GD Star Rating
loading...

About Hardono

Howdy! 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.

Possibly relevant:

Yesterday, I happened to kaypoh and stared into my friend’s laptop screen. Seeing that he was tinkering with JSON file, I told him about JSON Table Editor and how easy to edit JSON in tabular mode.

So he copy-pasted some part of his JSON string and hit “Load to Grid” button. Voila, it embarrassingly stuck forever at the loading dialog :D.

I apologized for wasting his time, and promised to look into it, once I reached home. Sitting comfy in front of my desktop at home, I start thinking about this bug. I didn’t have the exact JSON string, but I remember that it was a single object with two properties, and both properties are array of string. Below is my first attempt on reconstructing the error-triggering JSON string:

{
    "A0" : ["A0", "B0", "C0"], 
    "A1" : ["A1", "B1", "C1"]
}

But above JSON actually load correctly into the grid:

Not wanting to waste anymore time, I called up my friend and asking for the exact JSON string that he copy-pasted earlier. He sent it to me, but sort of warn me that the string is potentially confidential. Because of that, I can’t share the exact string here. But its structure is more or less like below:

{
    "A0.100.3" : ["A0:A1:A2=TRUE", "B0", "C0"], 
    "A1.200.1" : ["A1:A2:A3=TRUE", "B1", "C1"]
}

At first, I suspected that the string is not a valid JSON. But this was proven to be false. I parse it using JSON.parse and it returns the correct object. So, I continue to debug the code executing it step by step. After a while, I found where that exception was thrown. It was during creation of data Store object:

store = Ext.create('Ext.data.Store', {
    storeId: 'modelStore',
    model: 'mdl'
});
store.add(obj);
grid.reconfigure(store, _cols);

if (grid.filters)
    grid.filters.createFilters();

For now, I just added try-catch to prevent uncaught-exception which causing the loading dialog shown forever.

try {
    store = Ext.create('Ext.data.Store', {
        storeId: 'modelStore',
        model: 'mdl'
    });
    store.add(obj);
    grid.reconfigure(store, _cols);

    if (grid.filters)
        grid.filters.createFilters();
}
catch (eParse) {
    Ext.Msg.hide();
    setTimeout(function(){
        Ext.Msg.alert('Error', eParse);		
    }, 100);
}

The try-catch will catch all exception during data store creation and prompt the error:

Now let’s return to the JSON string and let’s examine it. I did say that the string is a valid JSON. You can validate this by going to your browser’s Web Developer Console, as I shown it below:

As we can see, when calling the object property directly (e.g. o.A0.100.3), we received the same exact exception as when we tried to load this string to grid. Therefore, we can conclude that deep down inside data store creation, the input object property was called directly instead of using array interface (e.g. o[“A0.100.3”]).

I’ll update again once I manage to patch the bug. Till then, cheers!

GD Star Rating
loading...

About Hardono

Howdy! 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.

Possibly relevant: