SteveSanderson / knockout.mapping

Object mapping plugin for KnockoutJS
Other
546 stars 767 forks source link

IE9 and Serialization #81

Closed rosshinkley closed 12 years ago

rosshinkley commented 12 years ago

A bit of a mystery has cropped up using knockout (2.1.0) and knockout mapping (2.1.2) in IE9. For some reason, array indices of objects get turned into parent objects. For example:

ko.mapping.toJSON(attachments);

produces something that looks like this in Chrome:

{
    "UserID": 432,
    "Attachments": [{
        "AttachmentID": 2,
        "OwnerID": 321,
        "DisplayName": "sample.pdf",
        "Description": "desc",
        "PostDate": "2012-06-01T09:24:43.817"
        }, {
        "AttachmentID": 3,
        "OwnerID": 432,
        "DisplayName": "sample3.pdf",
        "Description": "desc",
        "PostDate": "2012-06-05T14:01:00.693"
        }, {
        "AttachmentID": 4,
        "OwnerID": 543,
        "DisplayName": "sample2.pdf",
        "Description": "desc",
        "PostDate": "2012-06-05T14:01:49.18"
        }]
}

... but in IE9, produces something like this:

{
    "UserID": 432,
    "Attachments": {
    "0": {
        "AttachmentID": 2,
        "OwnerID": 321,
        "DisplayName": "sample.pdf",
        "Description": "desc",
        "PostDate": "2012-06-01T09:24:43.817"
    },
    "1": {
        "AttachmentID": 3,
        "OwnerID": 432,
        "DisplayName": "sample3.pdf",
        "Description": "desc",
        "PostDate": "2012-06-05T14:01:00.693"
    },
    "2": {
        "AttachmentID": 4,
        "OwnerID": 543,
        "DisplayName": "sample2.pdf",
        "Description": "desc",
        "PostDate": "2012-06-05T14:01:49.18"
    }
    }
}

This breaks my knockout bindings because the template is expecting attachments to be a first-order array.

Interestingly, json2's stringify returns the first output (which is what I'd expect).

Has anyone seen this behavior before? Any ideas on how to correct it?

sagacity commented 12 years ago

That's certainly quite odd! Would it be possible for you to create a small jsfiddle (or preferably a failing unit test in a fork of knockout.mapping) to reproduce the problem?

rosshinkley commented 12 years ago

I tried to make a jsfiddle to recreate the problem, but the dreaded IE9 mime type issue cropped up when I tried to reference the latest build on github directly. So, instead, I started tinkering with the simplest case I could come up with locally - put the original object together (see output 1) and call ko.mapping.toJSON(). That ought to present with the same behavior.

It ought to.

Much to my chagrin, I cannot recreate the problem in a sandbox. But, if I copy/paste the offending parts directly into the broken project, it shows the same behavior. Even with mimicking the setup of the broken project, the sandbox won't present this behavior. Hair: pulled.

I have a "workaround", but it isn't pretty. If i override the JSON object and force it to use JSON3, then do some stringify hocus pocus like this:

var jsonString = JSON.stringify(objToBind);
var reconstitutedObject = ko.utils.parseJson(jsonString);

... create the mapping from the reconstituted object and bind to the reconstituted object, the extra container seems to be gone. This suggests to me that there is something extra in the array definition that is being interpreted as a container, but after poking around in the guts of the main project, sniffing network traffic, and trying to drill down into how the server responds, I'm coming up short. I haven't drilled down into how knockout's serialization works, yet; I think that might be my next move. I was hoping it was something goofy that I had missed, or some sort of setup problem with the main project, but so far, I'm coming up short.

sagacity commented 12 years ago

Wow, what an investigation... I did just release a new version (2.2.0) of the mapping plugin. It's a long shot, but maybe it's worth trying it regardless.

rosshinkley commented 12 years ago

Thanks. :) The JSON stringify workaround was an (fortuitous!) accident, so at least I've got it (ahem) working.

Updating was worth a shot, but it does not seem to have fixed the issue. I don't know that I'll have much more time to devote to this today, but I'd still like to keep drilling into it to figure out what the root cause is. I'm becoming more and more convinced it's something with the setup of the project causing IE to misbehave. I'd say it might be just my setup, but I have at least been able to recreate the problem across other clients (read: I broke the QA build) for that project.

I'll let you know what I figure out!

sagacity commented 12 years ago

Okay! I certainly hope you can work it out. I'll close the issue for now then, but please feel very free to reopen it if you still feel the mapping plugin is the cause of the problem.