1

In latest free from from github posting images from form edit sends image key two times.

For example using testcase below post data contains:

------WebKitFormBoundaryHjeY1fJPAaaXE56n
Content-Disposition: form-data; name="Pilt"; filename="eeva.bmp"
Content-Type: image/bmp


------WebKitFormBoundaryHjeY1fJPAaaXE56n
Content-Disposition: form-data; name="_image_Pilt"


------WebKitFormBoundaryHjeY1fJPAaaXE56n
Content-Disposition: form-data; name="Pilt"

Note that name="Pilt" appears in tow times.

To reproduce, open code below in Chrome, select row, start form edit, select some image, active chrome developer tools and press submit button. Request payload shows that duplicate Pilt keys are posted.

How to fix this so that there are no duplicate keys on post like in earlier version ?

Testcase:

<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="utf-8">
    <meta http-equiv="X-UA-Compatible" content="IE=edge">
    <meta name="viewport" content="width=device-width, initial-scale=1">
    <title>http://stackoverflow.com/q/33628065/315935</title>
    <meta name="author" content="Oleg Kiriljuk">
    <link rel="stylesheet" href="http://ajax.googleapis.com/ajax/libs/jqueryui/1.11.4/themes/redmond/jquery-ui.css">
    <link rel="stylesheet" href="http://netdna.bootstrapcdn.com/font-awesome/4.4.0/css/font-awesome.min.css">
    <!--<link rel="stylesheet" href="jqGrid/css/ui.jqgrid.css">-->
    <link rel="stylesheet" href="http://rawgit.com/free-jqgrid/jqGrid/master/css/ui.jqgrid.css">
    <style>
        html, body { font-size: 75%; }
    </style>
    <script src="http://ajax.googleapis.com/ajax/libs/jquery/1.11.3/jquery.min.js"></script>
    <script src="http://ajax.googleapis.com/ajax/libs/jqueryui/1.11.4/jquery-ui.min.js"></script>

    <script src="http://malsup.github.io/jquery.form.js"></script>

    <script>
        $.jgrid = $.jgrid || {};
        $.jgrid.no_legacy_api = true;
        $.jgrid.useJSON = true;
    </script>
    <!--<script src="jqGrid/js/jquery.jqGrid.src.js"></script>-->
    <script src="http://rawgit.com/free-jqgrid/jqGrid/master/js/jquery.jqgrid.src.js"></script>
    <script>
    //<![CDATA[
    /*global $ */
    /*jslint browser: true */
    $(function () {
        "use strict";
        /*global $ */
        /*jslint plusplus: true, browser: true, eqeq: true */
        $(function () {
            "use strict";
            var mydata = [
                    { id: "10", _image_Pilt: null, invdate: "2013-11-01", name: "'", note: "note", amount: "200.00", tax: "10.00", closed: true, ship_via: "TN", total: "210.00" }
                ],
                editSettings = {


                    url: null,
                    useDataProxy: true,
                    dataProxy: function (opt, args) { dataProxyAjax(opt, args, 'Artpilt'); },


                    checkOnUpdate: true,
                    reloadAfterSubmit: false,
                    closeOnEscape: true,
                    savekey: [true, 13],
                    closeAfterEdit: true
                },
                addSettings = {
                    checkOnUpdate: true,
                    reloadAfterSubmit: false,
                    savekey: [true, 13],
                    closeOnEscape: true,
                    closeAfterAdd: true
                },
                delSettings = {
                },
                initDateEdit = function (elem) {
                    setTimeout(function () {
                        $(elem).datepicker({
                            dateFormat: "dd-M-yy",
                            showOn: "button",
                            changeYear: true,
                            changeMonth: true,
                            showButtonPanel: true,
                            showWeek: true
                        });
                    }, 50);
                },
                initDateSearch = function (elem) {
                    setTimeout(function () {
                        $(elem).datepicker({
                            dateFormat: "dd-M-yy",
                            changeYear: true,
                            changeMonth: true,
                            showButtonPanel: true,
                            showWeek: true
                        });
                    }, 50);
                },
                removeTheOptionAll = function (elem) {
                },
            dataProxyAjax = function (opts, act, entity) {
                //opts.url = $grid.jqGrid('getGridParam', 'url');
                if (opts.data._oper === "edit") {
                    opts.url = 'http://httpbin.org/status/200';
                }
                else {
                    opts.url = 'http://httpbin.org/status/201';
                }
                opts.iframe = true;
                var $form = $('#FrmGrid_' + $grid.jqGrid('getGridParam', 'id')),
                    ele;

                //use normal ajax-call when no files to upload
                //    if ($form.find(':file[value!=""]').size() == 0) {
                //        $.ajax(opts);
                //        return;
                //    }

                //Prevent non-file inputs double serialization
                ele = $form.find('INPUT,TEXTAREA,SELECT').not(':file');
                ele.each(function () {
                    $(this).data('name', $(this).attr('name'));
                    $(this).removeAttr('name');
                });

                //Send only previously generated data + files
                $form.ajaxSubmit(opts);
                //Set names back after form being submitted
                setTimeout(function () {
                    ele.each(function () {
                        $(this).attr('name', $(this).data('name'));
                    });
                }, 200);
            },

                $grid= $("#list")
                ;

            $("#list").jqGrid({
                useDataproxy: true,
                dataProxy: function (opt, args) { dataProxyAjax(opt, args, 'Artpilt'); },

                datatype: "local",
                data: mydata,
                colNames: ["", "Image","Select image", "Client", "Date", "Amount", "Tax", "Total", "Closed", "Shipped via", "Notes"],
                colModel: [
                    {name: "act", template: "actions"},


{    "label": "Pilt", "name": "_image_Pilt", "edittype": "image", "editoptions": {
        "src": ""
    }, "editable": true, "formatter": function (cell, options, row) {
        return '<img src=\"https://placehold.it/100x100\" />';
    }
, "search": false, "title": "", "width": 54
}, { "edittype": "file", "label": "", "name": "Pilt", "search": false, "title": "", "width": 54, "hidden": true, "editrules": { "edithidden": true }, "editable": true },

                    { name: "name", width: 60, editrules: { required: true } },
                    {name: "invdate", width: 80, align: "center", sorttype: "date",
                        formatter: "date", formatoptions: {newformat: "d-M-Y", reformatAfterEdit: true},
                        editoptions: {dataInit: initDateEdit, size: 14},
                        searchoptions: {dataInit: initDateSearch}},


                    {
                        name: "amount", width: 62, template: "number",
                        formatter: "number", formatoptions: { decimalSeparator: ",", thousandsSeparator: " ", decimalPlaces: 2, defaultValue: '0,00' },
                            editoptions: {
                                maxlength: 7,
                                type: "number",
                                max: "9999",
                                dataEvents: [
                                    {
                                        type: "blur",
                                        fn: function (e) {
                                                if (e.target.checkValidity()) {
                                                    $(e.target).removeClass("ui-state-error");
                                                } else {
                                                    $(e.target).addClass("ui-state-error");
                                                    alert(e.target.validationMessage);
                                                    $(e.target).focus();
                                                }
                                            }
                                    }
                                ]
                            }
                        },


                    //{ name: "amount", width: 70, formatter: "number", align: "right" },



                    { name: "tax", width: 50, formatter: "number", align: "right" },
                    {name: "total", width: 60, formatter: "number", align: "right"},
                    {name: "closed", width: 70, align: "center", formatter: "checkbox",
                        edittype: "checkbox", editoptions: {value: "Yes:No", defaultValue: "Yes"},
                        stype: "select",
                        searchoptions: {
                            sopt: ["eq", "ne"],
                            value: ":All;true:Yes;false:No",
                            dataInit: removeTheOptionAll
                        }},
                    {name: "ship_via", width: 100, align: "center", formatter: "select",
                        edittype: "select", editoptions: {value: "FE:FedEx;TN:TNT;IN:Intim", defaultValue: "TN"},
                        stype: "select",
                        searchoptions: {
                            sopt: ["eq", "ne"],
                            value: ":All;FE:FedEx;TN:TNT;IN:Intim",
                            dataInit: removeTheOptionAll
                        }},
                    {name: "note", width: 60, sortable: false, edittype: "textarea"}
                ],
                cmTemplate: {editable: true, searchoptions: {clearSearch: false }},
                rowNum: 10,
                rowList: [5, 10, 20],
                pager: true,
                gridview: true,
                rownumbers: true,
                autoencode: true,
                ignoreCase: true,
                sortname: "invdate",
                viewrecords: true,
                sortorder: "desc",
                caption: "Demonstrates implementating of local form editing",
                height: "100%",
                editurl: "http://httpbin.org/status/200",
                //editurl: "clientArray",
            }).jqGrid("navGrid", {}, editSettings, addSettings, delSettings, {
                multipleSearch: true,
                overlay: false,
                onClose: function () {
                    // if we close the search dialog during the datapicker are opened
                    // the datepicker will stay opened. To fix this we have to hide
                    // the div used by datepicker
                    $("div#ui-datepicker-div.ui-datepicker").hide();
                }
            }).jqGrid("filterToolbar", { defaultSearch: "cn" });
        });
    });
    //]]>
    </script>
</head>
<body>
    <div id="outerDiv" style="margin: 5px;">
        <table id="list"></table>
    </div>
</body>
</html>
Andrus
  • 26,339
  • 60
  • 204
  • 378

1 Answers1

1

You use useDataproxy option. Thus jqGrid don't send any data at all. If some problems exists than it should be probably in the code of dataProxyAjax or the code of jquery.form.js. jqGrid just prepare the data in postdata object. The object contains only one property with Pilt name. Thus any problems with "duplicate form key post" could be not a bug in free jqGrid.

If you want that free jqGrid use the same encoding of output characters as before, then you need just include autoEncodeOnEdit: true jqGrid option. Moreover you can use any custom encoding by usage of serializeEditData.

UPDATED: The problem was in the usage of jQuery.val() for filling of all fields of Add/Edit form. The changes was introduced to allow support of HTML5 input elements with new type values (number, color, range and so on). As the side effect jqGrid filled the fields which had the type image and file. It was the origin of the reported problem.

The problem should be fixed after posting the commit.

Oleg
  • 220,925
  • 34
  • 403
  • 798
  • If jqgrid 4.9.0 is used ( reference in code is changed to https://github.com/free-jqgrid/jqGrid/blob/v4.9.0/js/jquery.jqgrid.src.js ) posting works without issues. So this is jqgrid issue. How to diagnose or fix it? – Andrus Nov 28 '15 at 15:42
  • @Andrus: Do you examined the `postdata` in both cases ()? Where you see the difference? Do you tried to use `autoEncodeOnEdit: true` option of jqGrid? Do you have the same results? – Oleg Nov 28 '15 at 16:34
  • There is no postdata: edit form elemens are got using `$('#FrmGrid_' + $grid.jqGrid('getGridParam', 'id')` , copied to `iframe` and `submit()` in iframe is executed. `autoEncodeOnEdit: true` is used but problem persists. – Andrus Nov 28 '15 at 18:18
  • @Andrus: It seems to me that I found the reason. I will make some changed, do some tests and will append my answer finally. – Oleg Nov 28 '15 at 18:22
  • .Answer states that `serializeEditData` can used for custom encoding. Which is best way to upload file from form edit using `multipart/form-data` encoding ? If this is using serializeEditData, how `serializeEditData` can serialize file contents to this format? serializeEditData requires that all data must be in memory. There is related question in http://stackoverflow.com/questions/33945491/how-to-upload-image-in-form-edit-in-free-jqgrid-4-10 – Andrus Nov 28 '15 at 20:06
  • I tried `$.extend(true, $.jgrid.edit, { ajaxEditOptions: { contentType: "multipart/form-data" }` but this does not post in this format. How to fix this so that jqgrid can post in this format natively ? – Andrus Nov 28 '15 at 20:54
  • @Andrus: I updated my answer. Now the problem should be fixed. Thanks you for reporting the problem. – Oleg Nov 28 '15 at 21:38