Model is null after postback in pager
Asked Answered
A

2

6

On my page I have:

  • a 'filter' section - a couple of checkboxes and textboxes,
  • a 'search' button,
  • grid with paging where the results are displayed. The grid is from Telerik (http://demos.telerik.com/aspnet-mvc/grid/index1), but I don't think this matters.

Searching works OK - I can input some text or check a checkbox in the filter section and the appropriate results are displayed.

Paging works OK only if I use it when the page is loaded (that means before I click Search button, in this case the url is '...Home').

But if click search first (in this case the url will become '...Home/Search') and then try to go to another page on the grid then I get an exception in the Search method, because the model.Filter parameter is null (System.NullReferenceException: Object reference not set to an instance of an object.)

I tried to solve the problem in many different ways (with RedirectToAction method, storing the filter to session and use it in Search method,...) but no solution worked in all scenarios. Any ideas?

My simplified code:

HomeController:

public ActionResult Index()
{
    // On page load display all data without filters.
    var filter = new OverviewFilterModel
    {
        Type1 = true,
        Type2 = true,
        WorkingOrder = ""
    };
    ViewBag.Results = GetResults(filter);
    return View(new HomeModel { Filter = filter });
}

public ActionResult Search(HomeModel model)
{
    ViewBag.Results = GetResults(model.Filter);
    return View("Index");
}

public class OverviewFilterModel
{
    public bool Type1 { get; set; }
    public bool Type2 { get; set; }
    public string WorkingOrder { get; set; }
}

public class HomeModel
{
    public OverviewFilterModel Filter { get; set; }
    public IEnumerable<OverviewResultsModel> Results { get; set; }
}

View:

<!-- ... -->
@model HomeModel
<!-- ... -->

@using (Html.BeginForm("Search", "Home", FormMethod.Post, new { @class = "form-inline" }))
{
    <div class="form-group" style="margin-left: 135px;">
        @Html.CheckBoxFor(p => p.Filter.Type1)@Html.LabelFor(p => p.Filter.Type1, new { style = "margin: 0 15px 0 5px;" })
    </div>
    <!-- a bunch of other checkboxes -->
    <br />
    <div class="form-group">
        <label style="width: 130px; text-align: right;">Delovni nalog</label>
        @Html.TextBoxFor(p => p.Filter.WorkingOrder, new { @class = "form-control ecert-filter-small", @autocomplete = "off" })
    </div>
    <!-- a bunch of other textboxes -->
    <button class="k-button" id="button-refresh" style="margin: 10px 0 0 135px;">Refresh</button>
    <hr />
    @(Html.Kendo().Grid<OverviewResultsModel>()
        .BindTo((IEnumerable<OverviewResultsModel>)ViewBag.Results)
        .Name("gridOverview")
        .Events(p => p.Change("overviewOnRowSelect"))
        .Columns(columns =>
        {
            columns.Template(@<text>@Html.ActionLink("WorkingOrder", "Index", "WO", new { dn = @item.WorkingOrder }, new { @class = "selectable-dn" })</text>).Title("");
            columns.Bound(p => p.Type);
            columns.Bound(p => p.WorkingOrder);
            columns.Bound(p => p.Date);
            columns.Bound(p => p.ProductId);
            columns.Bound(p => p.ProductName);
        })
        .Selectable()
        .Pageable(p => p
            .Refresh(true)
            .PageSizes(true)
            .ButtonCount(10)
            .Messages(q =>
            {
                q.Display("{0} - {1} od {2} records");
                q.Empty("No data for selected filter");
                q.ItemsPerPage("Number of records per page");
            })
        )
        .DataSource(p => p.Server().PageSize(20).Model(q => { q.Id(r => r.WorkingOrder); }))
    )
}
Adnopoz answered 17/6, 2016 at 9:12 Comment(2)
Maybe you should check you model, and if it's null, handle this. Besides that, I can't understand, where's filter variable defined in your Index method? If you need to use some data through couple of pages, I will recommend you use TempData instead of ViewBag.Misprize
I edited my question - in Index method (when the page loads) the filter is empty so all data should be displayed. I also added the HomeModel class which is used in the View (@model HomeModel).Adnopoz
A
3

I solved this with the help of session objects - one for filter and one for result. Not the most elegant solution but it works.

public ActionResult Index()
{
    // On page load display all data without filters.
    OverviewFilterModel filter;
    if (Session["filter"] == null) {
        var filter = new OverviewFilterModel
        {
            Type1 = true,
            Type2 = true,
            WorkingOrder = ""
        };
    }
    else {
        filter = (OverviewFilterModel)Session["filter"];
    }

    if (Session["results"] == null){
        ViewBag.Results = GetResults(filter);
    }
    else{
        ViewBag.Results = Session["results"];
    }

    return View(new HomeModel { Filter = filter });
}

public ActionResult Search(HomeModel model)
{
    if (model.Filter == null)
    {
        model.Filter = (OverviewFilterModel)Session["filter"];
    }

    ViewBag.Results = GetResults(model.Filter);
    return View("Index");
}

private IEnumerable<OverviewResultModel> GetResults(OverviewFilterModel filter){
    var data = ...

    Session["results"] = data;
    Session["filter"] = filter;

    return data;
}
Adnopoz answered 21/6, 2016 at 13:16 Comment(0)
I
2

Probably this way helps by handle null value of HomeModel.Filter in Search method before executing GetResults(model.Filter):

public ActionResult Search(HomeModel model)
{
    if (model.Filter == null)
    {
        model.Filter = new OverviewFilterModel
        {
            Type1 = true,
            Type2 = true,
            WorkingOrder = ""
        };
    }
    ViewBag.Results = GetResults(model.Filter);
    return View("Index", new HomeModel { Filter = filter });
}

I just figured that null value should be handled by an if-condition to prevent NRE, CMIIW.

Impropriety answered 17/6, 2016 at 9:50 Comment(2)
This is not OK because in this case I loose the information about the filter. So for example I select a checkbox in the filter section and click Search. The correct data is displayed. But then I click on page 2 on the grid pager and the second page is displayed for ALL data because the original data for the filter is lost.Adnopoz
So, you need to store your filter in cookies, then retrieve it.Misprize

© 2022 - 2024 — McMap. All rights reserved.