免费 jqgrid 升级后如何修复表单编辑中的重复表单键 post

How to fix duplicate form key post in form edit after free jqgrid upgrade

最近从 github post 从表单编辑发送图像密钥两次。

例如使用下面的测试用例 post 数据包含:

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

请注意 name="Pilt" 出现了两次。

要复制,请打开下面 Chrome、select 行中的代码,开始表单编辑,select 一些图像,激活 chrome 开发者工具,然后按提交按钮。 请求负载显示重复的 Pilt 密钥被 posted.

如何解决此问题,以便 post 上没有像早期版本中那样的重复键?

测试用例:

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

您使用 useDataproxy 选项。因此 jqGrid 根本不发送任何数据。如果存在一些问题,那么应该可能在 dataProxyAjax 的代码或 jquery.form.js 的代码中。 jqGrid 只是准备 postdata 对象中的数据。该对象仅包含一个 属性,名称为 Pilt。因此,"duplicate form key post" 的任何问题都可能不是免费 jqGrid 中的错误。

如果您希望免费的 jqGrid 使用与以前相同的输出字符编码,那么您只需要包括 autoEncodeOnEdit: true jqGrid 选项。此外,您可以通过使用 serializeEditData.

来使用任何自定义编码

更新: 问题在于使用 jQuery.val() 来填写 Add/Edit 表单的所有字段。引入更改是为了支持 HTML5 具有新类型值的输入元素(numbercolorrange 等)。作为副作用,jqGrid 填充了 imagefile 类型的字段。这是所报告问题的根源。

问题应该在发布后得到解决 the commit