Celdor
Celdor

Reputation: 2607

Implementing pagin / sorting / filtering in View with POST Form

I have an application in MVC 4 / C# / Visual Studio 2010 SP1. It is to create UI for storing collections of books. The information I want to store are: a name of a collection, a date on creation, and the list of books. A number of books is to be added from the database that stores all the books. Actually, another view is to edit books themselves.

So far, I have designed my View such that it shows form fields for name of collection and date on creation. But underneath I included list of all books to be selected.

Selecting them in the edit / create view means they are added to collection. I thought I could implement paging / sorting / filtering for the list of books as the number may become too large to show it on one page. My idea is to add PartialView with a list of books. The PartialView can be invoked by jQuery by .post() that is trggered by events like clicking on a page number, table column etc. The PartialView would store a page no., a sort criterium, filter criteria in some hidden fields and based on their values it would generate portion of the list. Hidden fields would be updated from the model but would also pass paging / sorting back to action.

I run into problem of how to put everything together in POST form. I would like a user to click page numbers while the previously selected books would still be selected. I don't know how to refresh a PartialView and keep books' state. I hope it is possible. If not, what would you recommend?

Thanks

Below is my application.

The model of a book:

// Entity
public class Book
{
    public string Title { get; set; }
    public string Author { get; set; }
    public DateTime DatePublished { get; set; }
}

ViewModels:

// BookToSelect view model
public class BookToSelect : Book
{
    public bool Isselected { get; set; }

    public static IList<BookToSelect> MapBooksToBooksToSelect(IList<Book> list, bool isselected = false)
    {
        return list.Select(x => new BookToSelect() { //...})
    }
    public static IList<Book> MapBooksToSelectToBooks(IList<BookToSelect> list)
    {
        return list.Select(x => new Book() { //... })
    }
}

// List of books view model
public class ListOfBooks
{
    public IList<BookToSelect> Books { get; set; }
    public DateTime DayOnCreationThe { get; set; }
    public string CollectionName { get; set; }

    public static IList<Book> GetListOfBooks()
    {
        return new List<Book>() {
            // ... set of new Books() { },
        };
    }
}

Controller / Action:

public class TestCollectionController : Controller
{
    [HttpGet, ActionName("Edit")]
    public ActionResult Edit_GET()
    {
        ListOfBooks ViewModel = new ListOfBooks();
        ViewModel.Books = ListOfBooks.GetListOfBooksToSelect();

        ViewModel.DayOnCreation = DateTime.Today;
        ViewModel.CollectionName = "List of random books";
        return View(ViewModel);
    }

    [HttpPost, ActionName("Edit")]
    public ActionResult Edit_POST(ListOfBooks ViewModel)
    {
        return View(ViewModel);
    }
}

and View:

@using MvcDbContext.ViewModels
@model ListOfBooks
@{
    ViewBag.Title = Model.CollectionName;
}

<h2>@Model.CollectionName</h2>
@using (Html.BeginForm())
{
    @Html.EditorFor(m => m.CollectionName)
    @Html.EditorFor(m => m.DayOnCreation)
    <table>
        <tr>
            <th class="display-label">@Html.DisplayNameFor(m => m.Books.FirstOrDefault().Isselected)</th>
            <th class="display-label">@Html.DisplayNameFor(m => m.Books.FirstOrDefault().Title)</th>
            <th class="display-label">@Html.DisplayNameFor(m => m.Books.FirstOrDefault().Author)</th>
            <th class="display-label">@Html.DisplayNameFor(m => m.Books.FirstOrDefault().DatePublished)</th>
        </tr>
            @for (int i = 0; i < Model.Books.Count(); i++)
            {
                <tr>
                    @Html.EditorFor(m => m.Books[i])
                </tr>
            }
        <tr>
            <td colspan="3"><input type="submit" name="SaveButton" value="Save" /></td>
        </tr>
    </table>
}

Upvotes: 0

Views: 75

Answers (1)

Chris Pratt
Chris Pratt

Reputation: 239270

As you've already determined, if you switch out the HTML with the next page, all the inputs, included their state, are replaced as well. As a result, the only way to handle this is to offload the state into an input outside of the replacement.

The simplest way to handle this would most likely be creating a hidden input that will consist of a comma-delimited string of ids of selected items. Just add some JS that will watch the checkboxes or whatever and add or remove items from this hidden input. You can then just post this string back and use Split to turn it into a list of ids that you can use to query the appropriate books and add them to the collection on the entity.

Upvotes: 1

Related Questions