EXTJS – JsonWriter not respecting DateFormat used with JsonReader

computer_girl

Recently while working on a project that used Extjs as the front-end to a MySQL application, we came across an interesting issue with Extjs’s JsonStore.  The JsonStore automatically creates a Jsonreader that is used to map data coming from the MySQL application to the Extjs front-end.  The JsonReader has an optional dateFormat config property which allows the format of the incoming data to be read properly using the format delivered from MySQL.  While using the JsonWriter to update records from a EditorGrid, we noticed that the format that was sent back from the JsonWriter was using Extjs’s default dateFormat (03-04-2011T00:00:00).

It was that the JsonWriter was not respecting the dateFormat defined when mapping the data using JsonReader.  There would appear to be multiple hacks that could be used to fix, such as adding a Listener before the update that would modify the datefield, however we came across this little bit of code that works wonders.  This code will over-ride the default DataWriter class to use the dateFormat property defined in the JsonStore Field mappings.

//This over-ride fixes JsonWriter not using the JsonReader dateFormat when writing

Ext.override(Ext.data.DataWriter, { toHash : function(rec) {
var map = rec.fields.map,
data = {},
raw = (this.writeAllFields === false && rec.phantom === false) ? rec.getChanges() : rec.data,
m;

Ext.iterate(raw, function(prop, value){
if((m = map[prop])){
var key = m.mapping ? m.mapping : m.name;
if (m.dateFormat && Ext.isDate(value)) {
data[key] = value.format(m.dateFormat);
} else {
data[key] = value;
}
}
});
// we don't want to write Ext auto-generated id to hash. Careful not to remove it on Models not having auto-increment pk though.
// We can tell its not auto-increment if the user defined a DataReader field for it *and* that field's value is non-empty.
// we could also do a RegExp here for the Ext.data.Record AUTO_ID prefix.
if (rec.phantom) {
if (rec.fields.containsKey(this.meta.idProperty) && Ext.isEmpty(rec.data[this.meta.idProperty])) {
delete data[this.meta.idProperty];
}
} else {
data[this.meta.idProperty] = rec.id
}
return data;
}
});

 

5 thoughts on “EXTJS – JsonWriter not respecting DateFormat used with JsonReader

  1. Jim

    This is the exactly problem I am having. I am trying to implement the override you have on this post, but am not having much luck,

    I am putting this code into a file called Ext.Overrides.js
    That file is being included after my ext-all.js call in my page. It does not appear to be getting fired during execution. Is there something else that needs to be done to make this work?

    I am using ext 4.0.2

  2. Prodromus

    Jim, the code I posted was for Ext JS 3.x. I have not yet had to port that code over to Ext JS 4.x, however a quick glance shows me that DataWriter has been completely rewritten, there is no longer a ToHash method, which is why it is not working for you with 4.x.

    I have two suggestions. First, verify that this issue still exists with 4.x, I have not tested yet, so you want to make sure that 4.x still does not respect the DateFormat when writing. First glance looks as if it does not. Second, take a look at the source code for the 4.x getRecordData method within /src//data/Writer.js. It looks like you may be able to override in a similar manner as the 3.x code.

    I have to port this code over eventually, so if you can’t figure it out, check back. If you do, please post your solution to help save others some time and effort.

    Thanks!

  3. Jim

    Prodromus

    Thank you. That was the issue.

    Here is the override that fixes this issue for me.

    /*
    *
    * This override fixes JsonWriter not using the JsonReader dateFormat when writing
    * Modified from
    *
    */
    Ext.override(Ext.data.writer.Writer, {

    /**
    * Formats the data for each record before sending it to the server. This
    * method should be overridden to format the data in a way that differs from the default.
    * @param {Object} record The record that we are writing to the server.
    * @return {Object} An object literal of name/value keys to be written to the server.
    * By default this method returns the data property on the record.
    */
    getRecordData: function(record) {
    var isPhantom = record.phantom === true,
    writeAll = this.writeAllFields || isPhantom,
    nameProperty = this.nameProperty,
    fields = record.fields,
    data = {},
    changes,
    name,
    field,
    key;

    if (writeAll) {
    fields.each(function(field){
    if (field.persist) {
    name = field[nameProperty] || field.name;
    data[name] = record.get(field.name);
    }
    });
    } else {
    // Only write the changes
    changes = record.getChanges();
    for (key in changes) {
    if (changes.hasOwnProperty(key)) {
    field = fields.get(key);
    name = field[nameProperty] || field.name;
    if (field.dateFormat && Ext.isDate(changes[key]))
    {
    data[name] = Ext.Date.format(changes[key], field.dateFormat);
    }
    else
    {
    data[name] = changes[key];
    }
    }
    }
    if (!isPhantom) {
    // always include the id for non phantoms
    data[record.idProperty] = record.getId();
    }
    }
    return data;
    }
    });

  4. Prodromus

    Hey, that is great, I am glad you got it working. Did you update that code, or did you find it somewhere else? If you did, do you mind if I add a new Blog entry with it? I am sure it will help a lot of other folks, including me!

    Actually, I just noticed you posted in on the Sencha forum, I agree with the other guy on there, this is a bug that they need to fix.

    Thanks!

  5. Jim

    I basically took the data writer from the 4.0.2 code, and modified their function slightly to fit my needs. Nothing too fancy, and as you see I didnt even bother with the situation where writeAllFields is true (since I dont use that). Feel free to do whatever you’d like with it. Ultimately, your post is the one that led me to this answer 🙂

    Thanks again.

Leave a Reply

Your email address will not be published. Required fields are marked *