jqgrid:如何发送和接收行数据保持编辑模式 [英] jqgrid: how send and receive row data keeping edit mode

查看:78
本文介绍了jqgrid:如何发送和接收行数据保持编辑模式的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

jqGrid具有员工名称和员工ID列.

jqGrid has employee name and employee id columns.

如果employee name已更改,则应调用服务器验证方法来验证名称.应该从此方法返回的数据中更新当前行列.

If employee name has changed, server validate method should called to validate name. Current row columns should be updated from data returned by this method.

如果employee id已更改,则应调用服务器验证方法来验证ID. 应该从此方法返回的数据中更新当前行列.

If employee id has changed, server validate method should called to validate id. Current row columns should be updated from data returned by this method.

jqGrid最好保持编辑模式,以便用户可以继续更改,接受或拒绝更改.

Preferably jqGrid should stay in edit mode so that user has possibility to continue changing, accept or reject changes.

如何在内联和表单编辑中实现此功能? 我正在考虑以下可能性:

How to implement this in inline and form editing? I'm thinking about following possibilites:

可能性1.

将编辑规则与自定义验证程序一起使用

Use editrules with custom validator like

            editrules = new
            {
                custom = true,
                custom_func = function(value, colname) { ??? }
            },

问题:如何从所有列中获取数据,进行同步或异步调用以及使用此调用结果更新列.

Issues: How to get data from all columns, make sync or async call and update columns with this call results.

可能性2.

要求用户按Enter键保存行. 问题:如何查找已更改的列并将此列号传递给服务器. 如何通过服务器响应更新当前行数据.

Require user to press Enter key to save row. Issues: how to find which column was changed and pass this column number to server. How to update current row data from server response.

可能性3.

如Oleg最佳答案中所述使用模糊 jqgrid更改单元格值并保持在编辑模式

using blur as described in Oleg great answer in jqgrid change cell value and stay in edit mode

问题:如果输入数据并立即按Enter,则模糊不会触发.在这种情况下如何应用模糊?

Issues: blur does not fire if data is entered and enter is pressed immediately. How to apply blur in this case ?

在摘要中,服务器sice的计算/验证应如下进行:

In summary server sice calculation/validation should be dones as follows:

如果在更改的列中移出焦点并将焦点移出或输入,请在更改的列中按以保存,服务器端同步,或者如果不可能,则应调用异步方法.更改后的列名和当前编辑的行值(如edit方法中的值)将作为参数传递给此方法.

If column in changed and focus moved out or enter is pressed in changed column to save, server side sync or if not possible then async method should be called. Changed column name and current edited row values like in edit method are passed as parameters to this method.

此方法返回已编辑行的新值.当前编辑的行值应替换为该方法返回的值.

This method returns new values for edited row. current edited row values should be replaced with values returned by that method.

更新

Oleg答案假定主键已修改.这个因素并不重要.这是问题的新版本,没有主键和其他更新:

Oleg answer assumes that primary key is modified. This factor is not important. Here is new version of question without primary keys and other updates:

jqGrid具有产品条形码和产品名称列.

jqGrid has product barcode and product name columns.

如果product name已更改,则应调用服务器验证方法来验证名称.应该从此方法返回的数据中更新当前行列.

If product name has changed, server validate method should called to validate name. Current row columns should be updated from data returned by this method.

如果product barcode已更改,则应调用服务器验证方法来验证产品条形码. 应该从此方法返回的数据中更新当前行列.

If product barcode has changed, server validate method should called to validate product barcode. Current row columns should be updated from data returned by this method.

jqGrid应该保持在编辑模式,以便用户可以继续更改,接受或拒绝更改.

jqGrid should stay in edit mode so that user has possibility to continue changing, accept or reject changes.

如何在内联和表单编辑中实现此功能? 我正在考虑以下可能性:

How to implement this in inline and form editing? I'm thinking about following possibilites:

可能性1.

将编辑规则与自定义验证程序一起使用

Use editrules with custom validator like

            editrules = new
            {
                custom = true,
                custom_func = function(value, colname) { ??? }
            },

问题:如果输入元素失去焦点,则custom_func不会触发.在保存所有元素之前调用它.因此无法使用.

Issue: custom_func does not fire if input element loses focus. It is called before save for all elements. So it cannot used.

可能性2.

要求用户按Enter键保存行. 问题:如何查找已更改的列并将此列号传递给服务器. 保存方法应为已知列(名称或条形码更改顺序)并填写不同的列.这看起来不合理.

Require user to press Enter key to save row. Issues: how to find which column was changed and pass this column number to server. Save method should known column (name or barcode change order) and fill different columns. This looks not reasonable.

可能性3.

使用模糊:

colModel: [{"label":"ProductCode","name":"ProductCode","editoptions":{
"dataEvents":[
{"type":"focus","fn":function(e) { ischanged=false}},
{"type":"change","fn":function(e) {ischanged=true}},
{"type":"keydown","fn":function(e) {ischanged=true }},
{"type":"blur","fn":function(e) { if(ischanged) validate(e)} }
]},

要实现验证,我在以下代码中找到了来自Oleg的好答案 jqgrid更改单元格值并保持在编辑模式

To implement validate I found code from Oleg great answer in jqgrid change cell value and stay in edit mode

要求摘要:

如果在更改的列中移出焦点并将焦点移出或输入,请在更改的列中按以保存,服务器端同步,或者如果不可能,则应调用异步方法.更改后的列名和当前编辑的行值(如edit方法中的值)将作为参数传递给此方法.

If column in changed and focus moved out or enter is pressed in changed column to save, server side sync or if not possible then async method should be called. Changed column name and current edited row values like in edit method are passed as parameters to this method.

此方法返回已编辑行的新值.当前已编辑的行值应替换为该方法返回的值.

This method returns new values for edited row. current edited row values should be replaced with values returned by that method.

Update2

此问题与并发无关.这是单用户和jqGrid问题.更新是指单个用户更改产品名称或条形码,并且服务器应提供附加数据(产品ID和/或名称/条形码)来对此进行响应.

This question is not about concurrency. This is single user and jqGrid issue. Updating means that single user changes product name or barcode and server shoudl provide additonal data (product id and/or name/barcode) is responce of this.

更新4

我在下面尝试了代码. 如果用户输入新代码并按Enter键而不移动到其他行,则不会发生模糊并且不会调用验证.

I tried code below. If user enters new code and presses Enter without moving to other row, blur does not occur and validation is not called.

如果单元格脏了,如何在jqGrid保存方法中检测?或者其他想法,如果按下Enter键结束编辑而又不丢失更改后的外键单元格的焦点,如何强制运行此代码?

How to dedect in jqGrid save method if cell is dirty or other idea how to force this code to run if enter is pressed to end edit without losing focus from changed foreign key cell ?

function validate(elem, column) {
ischanged = false;
var i, form, row;
var postData = { _column: column  };
var colModel = $("#grid").jqGrid('getGridParam', 'colModel');
var formEdit = $(elem).is('.FormElement');
// todo: use jQuery serialize()  ???
if (formEdit) {
    form = $(elem).closest('form.FormGrid');
    postData._rowid = $("#grid").jqGrid('getGridParam', 'selrow');
    for (i = 0; i < colModel.length; i++)
        eval('postData.' + colModel[i].name + '="' + $('#' + colModel[i].name + '.FormElement', form[0]).val() + '";');
}
else {
    row = $(elem).closest('tr.jqgrow');
    postData._rowid = row.attr('id');
    for (i = 1; i < colModel.length; i++)
        eval('postData.' + colModel[i].name + '="' + $('#' + postData._rowid + '_' + colModel[i].name).val() + '";');
}
$.ajax('Grid/Validate', {
    data: postData,
    async: false,
    type: 'POST',
    success: function (data, textStatus, jqXHR) {
        for (i = 0; i < data.length; i++) {
            if (formEdit)
                $('#' + data[i].name + '.FormElement', form[0]).val(data[i].value);
            else
                $('#' + postData._rowid + '_' + data[i].name).val(data[i].value);
        }
    }
});
}

colModel定义为:

colModel is defined as:

{"name":"ProductBarCode",
"editoptions":    {"dataEvents":  
[{"type":"focus","fn":function(e) {ischanged=false}
},
{"type":"change","fn":function(e) {ischanged=true},
{"type":"keydown","fn":function(e) {if(realchangekey()) ischanged=true}
},{"type":"blur","fn":function(e) { if(ischanged) {  validate(       e.target,ProductBarCode')}}
}]},"editable":true}

推荐答案

这是问题中的一个,要避免就更容易避免.我必须提醒您我的建议(在

It's one from the problems which is much easier to avoid as to eliminate. I have to remind you about my advises (in the comments to the answer) to use immutable primary key, so that is, will be never changed. The record of the database table can be destroyed, but no new record should have the id of ever deleted record.

在任何并发控制实现中,首先使服务器 能够检测并发问题很重要.您的Web应用程序的两个(或更多)用户可能阅读了相同的信息,例如有关员工的信息.例如,该信息可以显示在jqGrids中.如果您允许更改员工ID,那么第一个问题将是检测并发错误.让我们一个用户更改员工ID,而另一个用户尝试根据先前加载的信息修改同一员工.用户提交中标之后,服务器应用程序将仅收到编辑"请求,但在数据库中找不到相应的记录.服务器将必须发送错误响应,而无需任何详细信息.因此, editRow errorfunc editGridRow 的事件处理程序errorTextFormat应该触发"reloadGrid"重新加载整个网格包含的内容.

On any concurrency control implementation it is important that the server will be first able to detect the concurrency problem. It can be that two (or more) users of your web application read the same information like the information about the employee. The information can be displayed in jqGrids for example. If you allow to change the employee id, than the first problem would be to detect concurrency error. Let us one user will change the employee id and another user will try to modify the same employee based on the previous loaded information. After the user submit the midification, the server application will just receive the "edit" request but will not find the corresponding record in the database. The server will have to sent error response without any detail. So the errorfunc of the editRow or the event handler errorTextFormat of the editGridRow should trigger "reloadGrid" reload the whole grid contain.

如果您允许编辑主键,那么我可以想象到更危险的情况,如前所述.可能是另一位用户不仅将当前编辑行的ID更改为另一值,而且还可以更改另一个记录的ID,以便其新ID与当前编辑ID相同.在这种情况下,保存行的请求将覆盖另一条记录.

If you allow to edit the primary key, then I can imagine more dangerous situation as described before. It can be that another user not only change the id of the current editing row to another value, but one could change the id of one more record so, that its new id will be the same as the current editing id. In the case the request to save the row will overwrite another record.

为防止此类问题并简化乐观并发控制,您可以添加一列表示可以修改的每个数据库表中时间戳的任何形式.我个人使用Microsoft SQL Server,并添加了用于添加类型时间戳). 行版本的值将与数据.将发送到服务器的修改请求将包含行版本 .如果将任何数据保存在数据库中,则SQL数据库将自动自动修改相应rowversion列中的相应值.通过以下代码,服务器可以非常轻松地检测并发错误

To prevent such problems and to simplify the optimistic concurrency control one can add an additional column which represent any form of the timestamp in every table of the database which could be modified. I personally use Microsoft SQL Server and add I used to add the non-nullable column of the type rowversion (the same as the type timestamp in the previous version of the SQL Server). The value of the rowversion will be send to the jqGrid together with the data. The modification request which will be send to the server will contain the rowversion. If any data will be save in the database the corresponding value in the corresponding rowversion column will be automatically modified by the SQL database. In the way the server can very easy detect concurrency errors with the following code

CREATE PROCEDURE dbo.spEmployeesUpdate
    -- @originalRowUpdateTimeStamp used for optimistic concurrency mechanism
    -- it is the value which correspond the data used by the user as the source
    @Id int,
    @EmployeeName varchar(100),
    @originalRowUpdateTimeStamp rowversion,
    @NewRowUpdateTimeStamp rowversion OUTPUT
AS
BEGIN
    -- SET NOCOUNT ON added to prevent extra result sets from
    -- interfering with SELECT statements.
    -- ExecuteNonQuery() returns -1, but it is not an error
    -- one should test @NewRowUpdateTimeStamp for DBNull
    SET NOCOUNT ON;

    UPDATE dbo.Employees
    SET Name = @EmployeeName
    WHERE Id=@Id AND RowUpdateTimeStamp=@originalRowUpdateTimeStamp;

    -- get the new value of the RowUpdateTimeStamp (rowversion)
    -- if the previous update took place
    SET @NewRowUpdateTimeStamp = (SELECT RowUpdateTimeStamp
                                  FROM dbo.Employees
                                  WHERE @@ROWCOUNT > 0 AND Id=@Id)
END

您可以在服务器应用程序的代码中验证是否将由存储过程dbo.spEmployeesUpdate设置输出参数@NewRowUpdateTimeStamp.如果未设置,则服务器应用程序可以引发DBConcurrencyException异常.

You can verify in the code of the server application that the output parameter @NewRowUpdateTimeStamp will be set by the stored procedure dbo.spEmployeesUpdate. If it's not set the server application can throw DBConcurrencyException exception.

因此,我认为您应该在数据库和服务器应用程序代码中进行修改以实现开放式并发控制.之后,如果发生并发错误,服务器代码应返回HTTP错误代码的响应. editRow 或事件的errorfunc editGridRow 的处理程序errorTextFormat应该重新加载当前修改行的新值.您可以使用更复杂的方式或只是重新加载网格并继续修改当前行.如果未更改行ID,则可以轻松找到新加载的行,并在重新加载网格后轻松开始对其进行编辑.

So in my opinion you should make modifications in the database and the servers application code to implement optimistic concurrency control. After that the server code should return response with HTTP error code in case of concurrency error. The errorfunc of the editRow or the event handler errorTextFormat of the editGridRow should reload the new values of the currently modified row. You can use either the more complex way or just reload the grid and continue the modification of the current row. In case of unchanged rowid you can easy find the new loaded row and to start it's editing after the grid reloading.

您可以在现有数据库中使用

In the existing database you can use

ALTER TABLE dbo.Employees ADD NewId int IDENTITY NOT NULL
ALTER TABLE dbo.Employees ADD RowUpdateTimeStamp rowversion NOT NULL
ALTER TABLE dbo.Employees ADD CONSTRAINT UC_Employees_NewId UNIQUE NONCLUSTERED (NewId)
GO

然后,您可以使用NewId代替jqGrid或您需要的任何其他地方的id. NewId可以与您的当前主键共存,直到您更新应用程序的其他部分以使用更有效的NewId.

Then you can use NewId instead of the id in the jqGrid or in any other place which you need. The NewId can coexist with your current primary key till you update other parts of your application to use more effective NewId.

更新:我认为并没有真正需要为并发错误实现任何复杂的错误校正.在我的客户的项目中,需要编辑的数据不能包含任何长文本.因此,简单的消息就足够了,它描述了无法保存当前修改的原因.用户可以手动重新加载整个网格,并验证他所编辑的行的当前包含位置.不应忘记,任何复杂的程序都可能给项目带来更多错误,实现起来很复杂,会延长开发预算,而且大多数额外的投资永远无法收回.

UPDATED: I don't think that one really need to implement any complex error correction for the concurrency error. In the projects at my customers the data which are need be edited can not contain any long texts. So the simple message, which describe the reason why the current modifications could not be saved, is enough. The user can manually reload the full grid and verify the current contain of the row which he edited. One should not forget that any complex procedures can bring additional errors in the project, the implementation is complex, it extend the development budget and mostly the additional investment could never paid off.

如果您确实需要实现编辑行的自动刷新,例如,我将永远不会在模糊"事件中实现单元格验证.与此相反,您可以在 editRow的errorfunc内部进行验证errorTextFormat事件处理程序内> editGridRow 表示服务器返回并发错误.如果发生并发错误,可以将当前编辑行的ID保存在一个变量中,该变量可以在loadComplete事件句柄内部进行访问.然后,显示错误消息后,您可以根据$('#list').trigger('reloadGrid',[{current:true}])重新加载网格(请参见这里).在loadComplete事件句柄内部,可以验证是否设置了中止的编辑行的变量.在这种情况下,可以调用 editRow editGridRow 并继续编辑字符串.我认为,当当前行更改时,页面的其他行也可能会更改.因此,重新加载当前页面会更好,因为仅重新加载一个当前单元格或网格的一行数据就可以了.

If you do need implement automated refresh of the editing row I would never implement the cell validation in "on blur" event for example. Instead of that one can verify inside of errorfunc of the editRow or inside of the errorTextFormat event handler of the editGridRow that the server returns the concurrency error. In case of the concurrency error one can save the id of the current editing row in a variable which could be accessed inside of the loadComplete event handle. Then, after displaying of the error message, one can just reload the grid with respect of $('#list').trigger('reloadGrid',[{current:true}]) (see here). Inside of loadComplete event handle one can verify whether the variable of the aborted editing row is set. In the case one can call editRow or editGridRow and continue the editing of the string. I think that when the current row are changed another rows of the page could be also be changed. So reloading of the current page is better as reloading of the data only one current cell or one row of the grid.

这篇关于jqgrid:如何发送和接收行数据保持编辑模式的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆