Kendo Grid multi column group based on object array

前提是你 提交于 2019-12-11 06:03:22

问题


I am relatively new to MVC (and Kendo) but I have managed to setup a grid which contains multi column headers using the columns.Group functionality.

@(Html.Kendo().Grid<Result>()
            .Name("myGrid")
            .Columns(columns =>
            {
                columns.Bound(c => c.ResultDateTime).Title("Date Time");

                foreach (Lot Lot in (Lot[])ViewBag.Lots)                
                {
                    columns.Group(group => group
                        .Title(Lot.LotNumber)
                        .Columns(info =>
                        {
                            info.Bound(Lot.Result.Count.ToString());
                            info.Bound(Lot.Result.Mean.ToString());
                            info.Bound(Lot.Result.SD.ToString());
                        }));
                }
                columns.Bound(c => c.StandardComment.Description).Title("Comment");
                columns.Bound(c => c.ReviewComment.Description).Title("Review Comment");
                columns.Command(command => { command.Destroy(); });
            })
            .Editable(editable => editable
                .Mode(GridEditMode.InLine)
                .DisplayDeleteConfirmation(true))
            .Pageable()
            .Navigatable()
            .Sortable()
            .Groupable()
            .Scrollable()
            .DataSource(dataSource => dataSource
                .Ajax()
                .Batch(true)
                .PageSize(20)
                .ServerOperation(false)
                .Events(events => events.Error("error_handler"))
                .Read("ResultsAsync_Read", "ResultEntry")
                .Destroy("ResultsAsync_Destroy", "ResultEntry")
             )
        )

As you can see I am trying to build the columns dynamically based on an array which has been setup and passed using ViewBag.

Controller async function which sets up ViewBag.Lots extracting the array from the top level IEnumerable<Result> object:

public async Task<ActionResult> ResultsAsync_Read([DataSourceRequest]DataSourceRequest request)
        {                
            IEnumerable<Result> controlSets = await _manager.ReadAsync(test);            
            ViewBag.Lots = controlSets.Select(x => x.LotResults);
            return Json(controlSets.ToDataSourceResult(request));
        }

When I run this, I get the following error when trying to access the ViewBag.Lots attribute in the foreach.

NullReferenceException: Object reference not set to an instance of an object.

Does someone know why I am getting this error and also if there is a more efficient way to achieve my goal?

EDIT: Instead of using the ViewBag to hold the list of Lot objects, I am using it to hold the maximum number of lots available in the entire List<Result>s. I have taken @ken2k's advice onboard and done this within the Index() function of the Controller:

public async Task<IActionResult> Index()
        {
            QCTest test = new Models.Acusera.QCTest();
            test.TestID = 3;
            IEnumerable<Result> controlSets = await _manager.ReadAsync(test);
            ViewBag.MaxLots = controlSets.Max(x => x.LotResults.Count);
            return View("~/Views/Acusera/DataEntry/ResultEntry.cshtml");
        }

Then I loop over the maximum number of lots available and create the columns required:

.Columns(columns =>
                {
                    columns.Bound(c => c.ResultDateTime).Title("Date Time");

                    for (int i = 0; i < ViewBag.MaxLots; ++i)
                    {
                        columns.Group(group => group
                            .Title("Test")
                            .Columns(info =>
                            {
                                info.Bound(x => x.LotResults[i].Result.Count);
                                info.Bound(x => x.LotResults[i].Result.Mean);
                                info.Bound(x => x.LotResults[i].Result.SD);
                            }));
                    }
                    columns.Bound(c => c.StandardComment.Description).Title("Comment");
                    columns.Bound(c => c.ReviewComment.Description).Title("Review Comment");
                    columns.Command(command => { command.Destroy(); });
                })

This results in a grid displaying like so:

So I have managed to create the number of multi-header columns required to display the data. However, I am now getting an error:

Uncaught TypeError: Cannot read property 'Result' of undefined


回答1:


Your ResultsAsync_Read method is an async method that will be called by the Kendo framework from a javascript AJAX call, i.e. after your page has been loaded and rendered.

This means that when your page is rendered, ViewBag.Lots is actually null, which throw the exception.

What you need is to initialize this value when you load the page, not inside your ResultsAsync_Read method. Basically:

public async Task<ActionResult> Index()
{
    // Gets the values BEFORE rendering the view
    IEnumerable<Result> controlSets = await _manager.ReadAsync(test);

    // The ViewBag property will be available from the Razor view            
    ViewBag.Lots = controlSets.Select(x => x.LotResults);

    // Returns the view that display the grid
    return this.View();
}

It's important to remember how the MVC stuff actually works. Basically the steps are:

  • the server receives a request on the .../Index route
  • the server executes the Index() action
  • as the action returns this.View() (which would be equivalent to this.View("Index")), it renders the Index.cshtml razor view (that means the ViewBag must be not null here)
  • if later you do AJAX calls such as ResultsAsync_Read, changing the ViewBag won't have any effect as the page is already rendered. The only thing you could do to modify your page, is to return some JSON, and change the DOM based on the JSON result from inside your AJAX callback (i.e. using jQuery/javascript).


来源:https://stackoverflow.com/questions/38631743/kendo-grid-multi-column-group-based-on-object-array

易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!