开发者问题收集

避免 Kendo Grid 搜索中的空值

2022-10-27
630

我是 Telerik 的新手,目前正在使用 ASP.Net Core Grid

我已经可以正常工作了,但现在我想添加搜索栏工具栏,因此我将其添加为:

@(Html.Kendo().Grid(Model)
  .Name("grid")
  .ToolBar(t => t.Search())
  .Search(s =>
                    {
                        s.Field(o => o.PrimaryContact.FirstName, "contains");
                    })

问题是 PrimaryContact.FirstName 可以为空,因此当我尝试搜索某些内容时,它会引发控制台错误:

Uncaught TypeError: Cannot read properties of null (reading 'FirstName')

同样的事情也发生在列上,我通过添加 ClientTemplate 解决了此问题,如下所示:

columns.Bound(x => x.PrimaryContact.FirstName)
       .ClientTemplate("#= PrimaryContact ? PrimaryContact.FirstName : '' #")

但是搜索没有客户端模板来处理此问题

我尝试使用 jQuery 将字符串的空值更改为空如:

 function onDataBound(e) {
 for (let i = 0; i < rows.length; i++) 
{
           const row = $(rows[i]);
           const dt = e.sender.dataItem(row);
           const firstName = dt.get("PrimaryContact.FirstName");
              if (firstName === null)
                 {
                     row[0].cells[2].innerHTML = "";
                 }
}
}

但是它不起作用。

如何避免搜索中的空值?问候

FullCode:

 @(Html.Kendo().Grid(Model)
                    .Name("grid")
                    .ToolBar(t =>
                    {
                        t.Excel();
                        t.Pdf();
                        t.Search();
                    })
                    .DataSource(dataSource => dataSource
                        .Custom()
                        .PageSize(20)
                        .Schema(schema =>
                        {
                            schema.Data(x => "function(d) { return validateData(d); }");
                        })
                    )
                    .Pageable(pager => pager
                        .Numeric(true)
                        .Info(true)
                        .PreviousNext(true)
                        .PageSizes(new [] { 10 ,25 ,50 })
                        .Position(GridPagerPosition.Bottom)
                        .Messages(m =>
                        {
                            m.ItemsPerPage("entries");
                            m.Display("Showing {0} - {1} of {2} entries");
                        })
                        )
                    .Sortable()
                    .Search(s =>
                    {
                        s.Field(o => o.Name, "contains");
                        s.Field(o => o.PrimaryContact.FirstName, "contains");
                        s.Field(o => o.PrimaryContact.PhoneNumber, "contains");
                        s.Field(o => o.PrimaryContact.EmailAddress, "contains");
                        s.Field(o => o.IsActive, "contains");
                    })
                    .Events(events => events.DataBound("onDataBound"))
                    .Columns(columns =>
                    {
                        columns.Bound(x => x.AdvertiserId)
                            .Hidden();
                        columns.Bound(x => x.Name)
                            .Title("Advertiser Name");
                        columns.Bound(x => x.PrimaryContact.FirstName)
                            .ClientTemplate("#= PrimaryContact ? PrimaryContact.FirstName : '' #")
                            .Title("Contact Name");
                        columns.Bound(x => x.PrimaryContact.PhoneNumber)
                            .ClientTemplate("#= PrimaryContact ? PrimaryContact.PhoneNumber : '' #")
                            .Title("Contact Phone");
                        columns.Bound(x => x.PrimaryContact.EmailAddress)
                            .ClientTemplate("#= PrimaryContact ? PrimaryContact.EmailAddress : '' #")
                            .Title("Contact Email");
                        columns.Bound(x => x.IsActive)
                            .Title("Status")
                            .ClientTemplate("<span class='badgeTemplate'></span>")
                            .Sortable(false);
                        columns.Template("<div class='btn-group'></div>")
                            .Title("").Width(100);
                    })
                    )

    <script type="text/javascript">
    function validateData(data)
        {
            for (const item of data) {
            if (!item.hasOwnProperty("PrimaryContact")) {
                    item["PrimaryContact.FirstName"] = { "FirstName": ""};
                }
            }
    
            return data;
        }
  </script>

我也尝试使用 BeforeEdit 事件

.Events(events => events.DataBound("onDataBound").BeforeEdit("onBeforeEdit")

function onBeforeEdit(e) {
      if(e.model.isNew()){
        e.PrimaryContact.FirstName = "";
      }
    }

但是它不起作用

1个回答

尽可能避免使用嵌套属性。您应该有一个自定义 ViewModel,它可以将所有内容(无论您的 Model 类是什么)扁平化。其次,asp.net API 的功能不如本机 javascript 库那么全面。无论如何,它只是在页面上生成 javascript 的通道,所以如果需要,不要害怕添加 javascript。

您尝试做的事情是不可能的。您可以构建一个适当的平面 ViewModel,或者您可以在将数据加载到网格之前拦截数据并进行变异。您可以使用数据源上的 schema 属性来执行此操作。您将定义一个自定义 javascript 方法。

还有一件事,我认为您的问题不是缺少 FirstName ,而是 PrimaryContact 为空。您可能可以毫不费力地修复此服务器端。但是,如果您从第三方 API 获取此信息,则以下是修复客户端的方法。

.DataSource(ds =>
{
    ds
        .Custom()
        .Transport(t =>
        {
            // ...
        })
        .Schema(x => .Data(x => "function(d) { return validateData(d); }"))
        // ...
        ;
})

或者,如果您只是使用 javascript 定义

dataSource: {
    // ...
    schema: { data: validateData }
}

然后,以下是使用 javascript 方法清理模型并修复您需要修复的任何属性:

function validateData(data)
{
    for (const item of data) {
    if (!item.hasOwnProperty("PrimaryContact")) {
            item["PrimaryContact"] = { "FirstName": ""};
        }
    }

    return data;
}

完整 dojo 示例在这里

BurnsBA
2022-10-28