【问题标题】:jqGrid - Unique ID for new rowjqGrid - 新行的唯一 ID
【发布时间】:2016-04-15 01:34:21
【问题描述】:

我正在尝试为添加到 jqGrid 的新行分配一个唯一 ID。我使用免费的 jqGrid 4.11.0,一个用于服务器端的 java rest 服务和用于数据库的 MS SQL。

inlineEditing: {

    ajaxSaveOptions: { contentType: "application/json" },
    serializeSaveData: function (postData) {

        var idArray = grid.getCol('id');
        var count = 0;
        var k = 1;

            while(postData.id.search('jqg') != '-1'){

                for(var i =0 ; i<idArray.length;i++){

                    if(k == idArray[i]){
                        count++;
                    }
                    if(count == 0){

                        postData.id = k  ;
                        break;                              
                    }
                }                       
                k++;
            }               
        return JSON.stringify(postData);
    }
}

我注意到 jqGrid 给出的默认 ID 是 jqg + 一个数字。关于如何制作当前未在任何数据库记录上使用的唯一 ID 的任何建议?我应该从服务器端执行此操作还是可以在 jqGrid 代码中执行此操作?

在晚上的某个时候,这段代码有点工作,并继续为所有新行提供 id 7 [即使它应该继续增加]。经过一些更改[不记得有什么更改],每次我单击保存以将新行提交到服务器时,页面冻结并且 chrome 建议我应该终止该进程。

请告诉我什么以及是否应该添加更多信息。

编辑1:

$(function () {

var grid = $('#grid'),
    checkboxEditOptionEvents = [

        {type : 'click', data: {'Yes': 'Yes'}, fn: function (e, id) {
            var checkboxCol = grid.getCol('sefDepartament'),
                ids = grid.jqGrid('getDataIDs'),
                numberOfCheckedBoxes = [],
                k;

            for (k = 0; k < ids.length; k++) {
                    if(checkboxCol[k] == 'Yes'){
                        numberOfCheckedBoxes.push(checkboxCol[k]);
                        if (numberOfCheckedBoxes.length == 1){
                            alert('Please deselect the other checked box first');
                            $(this).prop("checked",false);
                            numberOfCheckedBoxes = 0;
                        }
                    }
        }
    }}];

var experienceFunction = function(cellvalue, options ,rowObject){

            var joinYearVar =  rowObject.joinYear,
             YY = joinYearVar.slice(0,4),
             MM = joinYearVar.slice(5,7),
             DD= joinYearVar.slice(8,11);

            return moment("\"" +YY+MM+DD+"\"" , "YYYYMMDD").fromNow();

};

var checkboxFormatFunc = function(cellvalue, options ,rowObject){
    if(cellvalue == 'Yes'){
        return 'Yes';
    }
    return 'No';
};

var  afterSaveFunction =   function(id){

            var prenumeVar = grid.getCell(id, 'prenume').trim(),
                numeVar = grid.getCell(id,'nume').trim(),
                usernameVar =  numeVar +'.'+ prenumeVar,
                emailVar = usernameVar + '@test.com';
            usernameVar =usernameVar.replace(/\s/g , '').trim();
            emailVar = emailVar.replace(/\s/g , '');

            grid.setCell(id, 'username', usernameVar);
            grid.setCell(id, 'email', emailVar);

};

var colModelSettings = [

    {name:'id', label:'id',key: true,hidden: true, width:10,sorttype:'number',editable: false},     
    {name:'nume',label:'Nume',width:90, align: 'center',editable:true,searchoptions: {sopt: ['eq','bw','ew','cn']}, editrules:{required:true}, editoptions: {defaultValue: ' '},formatter: 'text'},
    {name:'prenume',label:'Prenume',width:100,editable:true,searchoptions: {sopt: ['eq','bw','ew','cn']},align: 'center',editrules:{required:true},editoptions: {defaultValue: ' '},formatter: 'text'},
    {name:'username',label:'Username',searchoptions: {sopt: ['eq','bw','ew','cn']},width:125,align: 'center'  },
    {name:'email',label:'Email',width:135,searchoptions: {sopt: ['eq','bw','ew','cn']},align: 'center'},
    {name:'sefDepartament',label:'Sef Departament',width:90,editable:true,align: 'center', stype:"select", searchoptions:{sopt: ['eq','ne'],value: "Yes:Yes;No:No"},formatter: checkboxFormatFunc,edittype:'checkbox',editoptions: { dataEvents: checkboxEditOptionEvents,value:'Yes:No', defaultValue: 'No' }},
    {name:'position',label:'Position',editable:true,stype: 'select',formatter: 'select',searchoptions: {sopt: ['eq','ne'],value: ' : ;position 1:position 1;position 2:position 2;position 3:position 3;position 4:position 4;position 5:position 5'},
    align: 'center',edittype:'select',editoptions:{defaultvalue: 'P0: ',value: ' : ;position 1:position 1;position 2:position 2;position 3:position 3;position 4:position 4;position 5:position 5'},width: 75},

    {name:'joinYear',label:'Join Year',formatter:'date', formatoptions: {newformat:'d-m-Y'}, datefmt: 'dd-mm-yyyy', editable:true,searchtype: 'datepicker',align: 'center',width: 70,
    searchoptions:{dateFormat:'dd-mm-yy',dataInit: function (elem){
        $(elem).datepicker({ showButtonPanel: true, dateFormat: 'yy-mm-dd'});},sopt: ['eq','ne']},

    editoptions:{size:20,defaultValue: ' ',dataInit: function (elem) {

        $(elem).datepicker({ showButtonPanel: true, dateFormat: 'dd-mm-yy'});
    }}},

    {name:'experience', label:'Experience', formatter: experienceFunction, searchoptions:{sopt: ['eq','bw','ew','cn']}, editable:'hidden', editoptions:{defaultValue: ' '},align: 'center',width: 60},
    {name:'actiuni',label: 'Actiuni',formatter: 'actions', formatoptions: {afterSave:afterSaveFunction},editable: false,sortable: false,search: false,width: 20 }
    ];

grid.jqGrid({

    pager: '#pager', 
    url: "/RestWithDatabaseConnection/rest/fetchData",
    editurl:'/RestWithDatabaseConnection/rest/update',
    datatype: "json",
    height: 250,    
    viewrecords: true,
    scrollOffset:0,
    sortorder: 'asc', 
    caption:'Employee List' ,
    autowidth: true,
    colModel: colModelSettings,
    beforeSelectRow : function(id){ 

                        var idsArray = grid.jqGrid('getDataIDs');
                        var i;
                        for(i=0;i<idsArray.length;i++){
                            if($('#'+idsArray[i]).is('[editable="1"]') ){
                            grid.editRow(idsArray[i],true);
                            return false;
                            }
                        }   
                        return true;
                    },

    inlineEditing: {

        ajaxSaveOptions: { contentType: "application/json" },
        serializeSaveData: function (postData) {

            var idArray = grid.getCol('id');
            var count = 0;
            var k = 1;

                while(postData.id.search('jqg') != '-1'){

                    for(var i =0 ; i<idArray.length;i++){

                        if(k == idArray[i]){

                            count++;
                        }
                        if(count == 0){

                            postData.id = k  ;
                            break;
                        }
                    }
                    k++;
                }

            return JSON.stringify(postData);
        }
    }
});


grid.jqGrid('navGrid', '#pager', {edit:false, add:false, delete:true, save:false, cancel:false, search:true, searchtext: 'Search', refresh:true},

        {},{},{     
                url: '/RestWithDatabaseConnection/rest/delete',
                mtype: 'DELETE',
                reloadAfterSubmit: true,
                ajaxDelOptions: {
                    contentType: "application/json",
                },
                serializeDelData: function(postdata) {

                    return JSON.stringify(postdata);

            }},{},{},{},{} );

grid.jqGrid('inlineNav','#pager',
{
    edit:true,
    edittext: 'Edit',
    save:true,
    savetext: 'Save',
    add:true,
    cancel: true,
    canceltext: 'Cancel',
    cancelicon: 'ui-icon-cancel',
    addicon:'ui-icon-plus',
    addtext: 'Add',
    addedrow: 'last',
    addParams: {

        position: 'last',
        addRowParams: { 

            aftersavefunc : afterSaveFunction,
            keys: true,
        }
            },
    editParams:{

        url: '/RestWithDatabaseConnection/rest/update',
        mtype : "POST",
        keys: true,
        aftersavefunc : afterSaveFunction,
    }
})})

Edit2 - 服务器对 fetchData 的响应:

[{"id":"3","nume":"Aladin","prenume":"Zoro","username":"Aladin.Zoro","email":"Aladin.Zoro@test.com","sefDepartament":"Yes","position":"position 4","joinYear":"2015-11-08","experience":"2 months"},

{"id":"2","nume":"Harap","prenume":"Alb","username":"Harap.Alb","email":"Harap.Alb@test.com","sefDepartament":"No","position":"position 1","joinYear":"2016-01-03","experience":"9 days  "},

{"id":"4","nume":"Don","prenume":"Homa","username":"Don.Homa","email":"Don.Homa@test.com","sefDepartament":"No","position":"position 4","joinYear":"2015-09-06","experience":"4 months"},

{"id":"5","nume":"Dorel","prenume":"Gigel","username":"Dorel.Gigel","email":"Dorel.Gigel@test.com","sefDepartament":"No","position":"position 4","joinYear":"2016-01-10","experience":"2 days"},

{"id":"1","nume":"Ivan","prenume":"Stefan","username":"Ivan.Stefan","email":"Ivan.Stefan@test.com","sefDepartament":"No","position":"position 2","joinYear":"2016-01-10","experience":"2 days"}]

【问题讨论】:

  • 我想您尝试解决一些仅由于您所做的其他设置而存在的问题。你写了关于 MS SQL 的文章。您应该至少有一张表需要添加新记录。数据库中的主键是如何定义的?通常将IDENTITYId 定义为Id int IDENTITY PRIMARY KEY CLUSTERED。因此,数据库生成值。你是如何定义 jqGrid 的?你用的是哪个colModel?如果您没有id 列,那么您没有问题。添加新行后,您可以从服务器重新加载 jqGrid,您将获得服务器生成的 id。
  • 你好,奥列格!我在 jqgrid 中有一个 ID 列,我在 MS SQL 表中也有一个 ID 列 [PK],我从中获取数据并发送新信息。我不知道表列的 IDENTITY 函数。如果我将 IDENTITY 设置为表列,则数据库将根据我的理解自动生成 ID,但如果我要添加一个新行,它将有一个由数据库生成的 ID 和一个由 jqGrid 在它之前生成的本地 ID不会处理对新行的刷新和编辑。我怎么能解决这个问题?行发布后 jqGrid 重新加载触发器会处理它吗?
  • 能否包含一些您使用的 JavaScript 代码和一个用于与服务器通信的 JSON 格式示例? MS SQL 中的 int IDENTITY(或 @ MySQL 中的 987654330@) 在我看来是主键的最佳选择。 jqGrid首先创建temporary local rowid,但是它可以在收到服务器的响应后更新它。有很多方法可以更新 id。最佳选择取决于您实施的内容。如果您显示网格进行编辑并允许用户创建新行,那么重新加载将是最佳选择。
  • 如果您显示一个空网格并且用户需要一个接一个地填充许多行,那么重新加载网格可能不是最佳选择,您应该在aftersavefunc回调中实现更新rowid .服务器应该在editurl 的响应中返回新的rowid,回调aftersavefunc 应该使用类似$("#" + rowid).attr("id", newRowid) 的东西来更新rowid。确切的代码可能取决于您使用的colModel 以及服务器响应的格式。您可以使用rowversion (timestamp) 列进行并发检查并对其进行更新。
  • 我添加了整个 jqGrid 代码。我理解这两个想法,我会确保两者都尝试。我有信心让它发挥作用。目前 SQL 服务器已关闭,我无法获取服务器生成的 JSON 示例。如果您愿意,您可以发布答案,以便我将其设置为正确。一旦服务器备份,我就开始在它上面工作。谢谢!

标签: java jquery mysql jqgrid free-jqgrid


【解决方案1】:

以下是解决您的主要问题和改进您发布的 JavaScript 代码的一些建议。

首先,本地编辑场景需要locally生成新的rowids。应该在服务器上生成新的 rowids ,以防将后端的数据保存在数据库中。典型的实现包括在 every 表中将PRIMARY KEY 定义为int IDENTITY。它使 id 唯一且固定。删除某些行并创建新行将永远不会被解释为对旧行的编辑,因为新行将始终获得新的 id,它以前从未使用过(在表中)。

要利用在服务器端生成的 id,主要有两种选择:

  1. 在每次添加行操作后重新加载网格。
  2. 在编辑时扩展与服务器的通信,以便服务器将在数据库表中生成的新 id 返回给 jqGrid。在服务器上成功创建行后,可以使用aftersavefunc 回调(仅用于添加新行)更新rowid。 RESTful 服务的许多标准实现会在添加或编辑时返回 完整的行数据 包含 id。可以使用aftersavefunc 回调中的数据并使用$("#" + rowid).attr("id", newRowid); 之类的东西来更新新行。它一种将 id 保存在一些额外的列中(比如你使用隐藏的id 列)然后一个应该使用setCell 方法来更新单元格。

第一个选择是最简单的,我建议你首先实现它。只有当重新加载网格不能满足用户,不断添加许多行时,你才应该多写一点代码来实现第二种情况。

您当前的代码使用inlineNav 进行添加和编辑操作,使用内联编辑实现,使用方法navGrid 进行删除操作,使用表单编辑实现。表单编辑,包括删除,默认使用reloadAfterSubmit: true 选项。这意味着删除每一行后,将从服务器(从url: "/RestWithDatabaseConnection/rest/fetchData")重新加载网格。您可以通过将afterSaveFunction 替换为以下内容来解决您的主要问题:

var afterSaveFunction = function () {
        $(this).trigger("reloadGrid", [{current: true, fromServer: true}]);
    };

选项current 用于在重新加载后保持当前选择和选项fromServer: true 仅在您另外使用loadonce: true 选项时才有意义。您可以使用navGridreloadGridOptions: {fromServer: true} 选项在单击导航栏的刷新/重新加载按钮时强制重新加载数据从服务器。如果您没有太多需要在网格中显示的数据(例如少于 1000 行),那么建议您使用这种行为。

一些更常见的建议来改进你的代码:

您可以考虑使用height: "auto" 代替height: 250,并通过指定rowNum 值来管理网格的最大高度。在这种情况下将不需要选项scrollOffset: 0

从服务器返回的数据格式看起来如此,您没有实现服务器端的分页、排序和过滤。您应该使用 loadonce: trueforceClientSorting: true 选项。 loadonce: true 通知 jqGrid 将 all 从服务器返回的数据本地保存在内部 data 参数中。您可以随时使用$('#grid').jqGrid("getGridParam", "data") 访问阵列。 rowNum 的值(默认值为 20)将用于 local 分页。 sortnamesortorder 将用于本地 排序。您将使用搜索对话框(由navGrid 添加)或过滤器工具栏(由filterToolbar 添加)进行本地 搜索/过滤。它简化了服务器代码,从用户的角度提高了网格的性能,并简化了服务器和客户端之间的接口。您可以在服务器上使用经典的 RESTful 接口,无需任何扩展。

另一句话:我建议您删除不需要的隐藏id 列(name:'id', label:'id', key: true, hidden: true, ...)。 rowid 的信息将保存在行的id 属性(&lt;tr&gt; 元素)中,并且不需要在每一行的隐藏&lt;td&gt; 元素中保存重复信息。

您的代码还有许多其他部分可以改进。例如,您在服务器端使用的 DELETE 操作似乎很奇怪。您使用mtype: 'DELETE',但您将请求的body 内已删除行的ID 发送到服务器,而不是将其附加到URL。对应于标准,HTTP DELETE 应该包含 no body。您可以使用 jqGrid 选项 formDeleting 指定所有删除选项,您可以将 url 参数定义为函数:

formDeleting: {
    mtype: "DELETE",
    url: function (rowid) {
        return "/RestWithDatabaseConnection/rest/delete/" + rowid;
    },
    ajaxDelOptions: { contentType: "application/json" },
    serializeDelData: function () {
        return "";
    }
}

您需要修改/RestWithDatabaseConnection/rest/delete/ 的服务器代码以使用相同的通信协议并从URL 中获取deleted from 的ID。

你可以使用free jqGrid的navOptions参数来指定navGrid的选项:

navOptions: { edit: false, add: false }

searchtext: 'Search' 和您使用的其他选项似乎有默认值,我在那里删除了)。

为了更接近 REST 标准,可以使用 HTTP PUT 操作进行行编辑,使用 HTTP POST 添加新行。您应该在后端为这两个操作实现 不同的 入口点。您已经使用了/RestWithDatabaseConnection/rest/update,并且可以实现/RestWithDatabaseConnection/rest/create 来添加新行。例如,您可以使用以下inlineEditing 更改来实现该场景:

inlineNavOptions: { add: true, edit: true },
inlineEditing: {
    url: function (id, editOrAdd) {
        return "/RestWithDatabaseConnection/rest/" +
            (editOrAdd === "edit" ? "update" : "create");
    },
    mtype: function (editOrAdd) {
        return editOrAdd === "edit" ? "PUT" : "POST";
    },
    keys: true,
    serializeSaveData: function (postData) {
        return JSON.stringify(dataToSend);
    },
    aftersavefunc: function () {
        $(this).trigger("reloadGrid", [{current: true, fromServer: true}]);
    },
    addParams: {
        addRowParams: {
            position: "last",
            serializeSaveData: function (postData) {
                var dataToSend = $.extend({}, postData);
                // don't send any id in case of creating new row
                // or to send `0`:
                delete dataToSend.id; // or dataToSend.id = 0; 
                return JSON.stringify(dataToSend);
            }
        }
    }
}

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2022-08-24
    • 2017-03-17
    • 2013-02-25
    • 2018-06-05
    • 2015-12-24
    相关资源
    最近更新 更多