我有一个具有 InCell
编辑功能的 Kendo 网格,可以将创建/更新的记录批量发送到服务器 (.Batch(true)
)。
下面是网格定义的简化示例:
@(Html.Kendo().Grid<TagEditingGridViewModel>()
.Name("...")
.Columns(c =>
{
c.Bound(e => e.TagText);
c.Bound(e => e.Description);
})
.Editable(e => e.Mode(GridEditMode.InCell))
.DataSource(d => d
.Ajax()
.Batch(true)
.Model(m => m.Id(e => e.ID))
//.Events(e => e.Error("...").RequestEnd("..."))
// Read, Update, Create actions
)
)
网格处理 Tag
项,这些项的 TagText
属性中必须具有唯一的非空值。
下面是网格的模型类及其验证属性:
public class TagEditingGridViewModel
{
public int ID { get; set; }
[Required(AllowEmptyStrings = false, ErrorMessage = "A tag text is required.")]
[StringLength(50, ErrorMessage = "Text cannot be longer than 50 characters")]
public string TagText { get; set; }
[StringLength(250, ErrorMessage = "Description cannot be longer than 250 characters")]
public string Description { get; set; }
}
[StringLength]
属性触发客户端验证,当字段为空时 [Required]
属性也会触发客户端验证。但当 TagText
字段仅为空格时,仍然需要服务器端验证,并检查唯一性。
此服务器端验证需要在更新现有记录和创建新记录时进行。这就是问题开始的地方。对于现有记录,模型在数据库中有一个 ID
,可用于在网格中查找相应的行。但是未通过验证的新记录不会在数据库中获得ID
,并且在网格中没有(唯一的)ID
rows - 它设置为 0
,因此您无法从该属性中识别行。
在 此帖子 在 Kendo 论坛中, Telerik 员工发布了一个解决方案,通过 InCell
和批量编辑在 Kendo 网格中显示服务器端验证错误。不幸的是,他们只显示更新时的解决方案,而不是创建时的解决方案。
在他们建议的解决方案中,他们使用网格数据源的 onError
事件,在其中使用模型的 ID 字段查找网格中的行。
// Controller:
currentErrors.Add(new Error() { id = model.LookupId, errors = errorMessages });
// JavaScript:
var item = dataSource.get(error.id);
var row = grid.table.find("tr[data-uid='" + item.uid + "']");
在我的创建操作中,我循环遍历传入的项目并将模型状态字典中的键设置为“models[i].TagText
”。当 TagText
是仅包含空格的字符串时,[Required]
属性会捕获此服务器端,并以相同的格式添加模型状态错误。
// items: List<TagEditingGridViewModel>
for (int i = 0; i < items.Count(); i++)
{
// check for uniqueness of TagText ...
// this is the way the validation attributes do it
ModelState.AddModelError($"models[{i}].TagText", "Tag text must be unique.");
}
return Json(items.ToDataSourceResult(request, ModelState), JsonRequestBehavior.AllowGet);
在我的网格中,我可以向 RequestEnd
事件添加一个处理程序,该处理程序可以访问请求类型(读取、创建或更新)、从服务器发回的数据(这将是 items
),以及任何模型状态错误。
但我仍然遇到一个问题,即我无法将 ID 为 0 的项目映射到网格中的行。是否可以保证 items
仍保持发送时的顺序,即它们在 DOM 中的顺序?
I have a Kendo Grid with InCell
editing that sends created/updated records to the server in batches (.Batch(true)
).
Here's a pared-down example of the grid definition:
@(Html.Kendo().Grid<TagEditingGridViewModel>()
.Name("...")
.Columns(c =>
{
c.Bound(e => e.TagText);
c.Bound(e => e.Description);
})
.Editable(e => e.Mode(GridEditMode.InCell))
.DataSource(d => d
.Ajax()
.Batch(true)
.Model(m => m.Id(e => e.ID))
//.Events(e => e.Error("...").RequestEnd("..."))
// Read, Update, Create actions
)
)
The grid handles Tag
items, which must have a unique, non-empty value in the TagText
property.
Here's the grid's model class, with its validation attributes:
public class TagEditingGridViewModel
{
public int ID { get; set; }
[Required(AllowEmptyStrings = false, ErrorMessage = "A tag text is required.")]
[StringLength(50, ErrorMessage = "Text cannot be longer than 50 characters")]
public string TagText { get; set; }
[StringLength(250, ErrorMessage = "Description cannot be longer than 250 characters")]
public string Description { get; set; }
}
The [StringLength]
attribute triggers client-side validation, as does the [Required]
attribute when the field is empty. But server-side validation is still needed when the TagText
field is whitespace only, and to check uniqueness.
This server-side validation needs to take place both on updating an existing record and on creating a new record. That's where the problem begins. For an existing record, the model has an ID
in the database that can be used to find the corresponding row in the grid. But a new record that does not pass validation does not get an ID
in the database and does not have a (unique) ID
in the grid rows - it is set to 0
, so you can't identify a row from that property.
In this post in the Kendo forums, a Telerik employee has posted a solution to showing a server-side validation error in a Kendo grid with InCell
and batch editing. Unfortunately, they only show the solution on update, not on create.
In their suggested solution, they use the onError
event of the grid's DataSource, where they find the the row in the grid using the model's ID field.
// Controller:
currentErrors.Add(new Error() { id = model.LookupId, errors = errorMessages });
// JavaScript:
var item = dataSource.get(error.id);
var row = grid.table.find("tr[data-uid='" + item.uid + "']");
In my create action, I loop through the incoming items and set the key in the model state dictionary to "models[i].TagText
". When the TagText
is a string that only contains whitespace, the [Required]
attribute catches this server-side, and adds a model state error in that same format.
// items: List<TagEditingGridViewModel>
for (int i = 0; i < items.Count(); i++)
{
// check for uniqueness of TagText ...
// this is the way the validation attributes do it
ModelState.AddModelError(quot;models[{i}].TagText", "Tag text must be unique.");
}
return Json(items.ToDataSourceResult(request, ModelState), JsonRequestBehavior.AllowGet);
In my grid, I can add a handler to the RequestEnd
event, which has access to the request type (read, create, or update), the data sent back from the server (which would be items
), and any model state errors.
But I still have the problem that I'm not able to map items with an ID of 0 to rows in the grid. Is there any guarantee that the items
are still in the same order they were sent, and that that is the order they are in the DOM?
发布评论
评论(1)
以下是我最终解决此问题的方法:
我首先修改了网格视图模型以包含 Kendo 网格行 UID 的属性。
我向网格的
DataSource
添加了两个事件(而不是向整个网格添加)。在
Change
事件中,当操作为"add"
(添加新行时)时,我将数据项的KendoRowUID
属性设置为该行的 UID。根据我需要在页面上显示
ModelState
错误的信息,我在控制器中创建了此方法。它只是获取我需要的字段并将它们粘贴到 JSON 对象字符串中,稍后我可以在 JavaScript 中对其进行反序列化。我在
""
键下添加了所有ModelState
错误,以便稍后(第 7 步),它们全部显示在e.errors[""].
我创建此方法是为了修改任何现有的
ModelState
错误以适应新格式。这是必要的,因为[Required(AllowEmptyStrings = false)]
属性确实捕获空字符串,但仅限于服务器端(空字符串不会在客户端捕获)验证)。(这可能不是最有效或最好的方法,但它确实有效。)
在创建/更新网格操作中,如果有任何
,我会调用
错误已存在。并根据需要进行额外验证。AlterModelError
方法ModelState在创建/更新网格操作结束时,我确保在调用
ToDataSourceResult
时包含ModelState
字典:最后,在网格的
DataSource< /code> 的
Error
事件,我...检查事件
errors
属性中是否有错误向网格的
DataSource
同步事件添加一次性处理程序在该同步事件处理程序中,循环遍历所有错误,并且
将字符串解析为 JSON 对象
找到
行。
如果该项目已存在于数据库中,则可以使用其
ID
字段从DataSource
获取该项目,并可以从那里获取该行。如果该项目是新创建的项目,其ID
仍设置为0
,因此使用 JSON 对象的kendoRowUid
属性。< /p>使用 JSON 对象的
field
属性来定位行内正确的列(以及单元格)将一个元素附加到显示验证消息的单元格
Here's how I ended up solving this issue:
I first modified my grid view model to include a property for the Kendo grid row's UID.
I added two events to the grid's
DataSource
(not to the grid as a whole).In the
Change
event, when the action was"add"
(when a new row is added), I set the data item'sKendoRowUID
property to the row's UID.Based on what information I needed to show the
ModelState
errors on the page, I created this method in my controller. It simply takes the fields I needed and sticks them into a JSON object string that I can later deserialize in JavaScript.I added all
ModelState
errors under the key""
, so that later (step 7), they all show up undere.errors[""]
.I created this method to modify any existing
ModelState
errors to fit the new format. This is necessary because the[Required(AllowEmptyStrings = false)]
attribute does catch empty strings, but only server-side (empty strings don't get caught in client-side validation).(This may not be the most efficient or best way to do it, but it works.)
In the create/update grid actions, I call the
AlterModelError
method if there are anyModelState
errors already present. And did additional validation as necessary.At the end of the create/update grid actions, I made sure to include the
ModelState
dictionary when callingToDataSourceResult
:Finally, in the grid's
DataSource
'sError
event, I ...Check if there are any errors in the event
errors
propertyAdd a one-time handler to the grid's
DataSource
sync eventIn that sync event handler, loop through all the errors, and
Parse the string into a JSON object
Find the
<tr>
row.If the item already exists in the database, its
ID
field can be used to get the item from theDataSource
, and the row can be gotten from there. If the item was a newly created item, itsID
is still set to0
, so thekendoRowUid
property of the JSON object is used.Use the
field
property of the JSON object to locate the correct column (and thus, cell) within the rowAppend an element to the cell that shows the validation message