Home > Software engineering >  Avoid null values from Kendo Grid search
Avoid null values from Kendo Grid search

Time:10-29

I'm new to using Telerik, and I am currently working on a ASP.Net Core Grid

So I have it working, but now I want to add the search bar toolbar, so I added it as:

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

The problem is that PrimaryContact.FirstName can be null, so when I try to search for something, it throws a console error:

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

This same thing happen on the columns and I solve it adding ClientTemplate as:

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

But Search has no a client template to handle this

I tried to change the null value for the string empty with jQuery as:

 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 = "";
                 }
}
}

But it does not work.

How can I avoid the null values from the search? Regards

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>

I also tried using BeforeEdit event

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

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

But it does not work as well

CodePudding user response:

Probably avoid using nested properties whenever possible. You should have a custom ViewModel that flattens everything (whatever your Model class is). Second, the asp.net API is not as full featured as the native javascript library. It's just a passthrough to generate javascript on the page anyway, so don't be afraid to add javascript if you need to.

What you're trying to do isn't possible. You can build a proper flat ViewModel, or you can intercept data and mutate before loading it into the grid. You do that using the schema property on the datasource. You'll define a custom javascript method.

One more thing, I think your problem is not that FirstName is missing, it's that PrimaryContact is null. You can probably fix this server side without too much hassle. But here's how to fix it client side, if, for example, you're getting this from a 3rd party API.

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

Or if you just use the javascript definition

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

Then here is the javascript method to cleanup your model with whatever properties you need to fix:

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

    return data;
}

Full dojo example here

  • Related