c# - ¿Cómo aplico el filtro al paginar en Asp.net MVC y entidad Framework?
asp.net-mvc entity-framework (3)
Creo que una mejor manera debería ser volver a ver los filtros en
ViewBag
.
Puedes hacer algo como a continuación:
@Html.PagedListPager(
Model.Tasks, id =>
Url.Action("Index", new { id,
Status = ViewBag.Status , AnotherFilterValue = ViewBag.AnotherFilterValue, ... }))
Pero tenga en cuenta para probar
ViewBag.Status
para el valor nulo.
Si tiene un valor, colóquelo en la lista de parámetros de ruta; de lo contrario, establezca un
ActionLink
predeterminado.
Luego, dentro de la acción POST, espera un int anulable como a continuación:
public ActionResult Index(int? id, int? status, ...)
{
int pageNumber = (id ?? 1);
if (ModelState.IsValid)
{
using(var connection = new Context())
{
if(status != null)
{
ViewBag.Status = status.value;
model.Tasks = connection.Tasks
.Where(task => task.Status == status.value)
.ToPagedList(pageNumber, 30);
}
else
{
model.Tasks = connection.Tasks
.ToPagedList(pageNumber, 30);
}
}
}
return View(model);
}
Tengo una aplicación web que está escrita usando el framework ASP.NET MVC.
En mi
Homecontroller
tengo una acción llamada
Index
que responde a una solicitud
Get
.
En esta acción, creo páginas usando la biblioteca
IPagedList
para dividir los registros en varias páginas.
Mi
Index@HttpGet
parece a esto
public ActionResult Index(int? id)
{
using(var connection = new Context())
{
int pageNumber = (id ?? 1);
var presenter = new Presenter
{
Presenter = pageNumber,
Tasks = connection.Tasks.ToPagedList(pageNumber, 30),
Form = new TasksFiltersViewModel()
}
return View(presenter);
}
}
También tengo una acción llamada
Index
que responde a la solicitud de
Post
que aplica algunos filtros.
Entonces, en la solicitud de
Post
, hago algo como esto
[HttpPost]
[ValidateAntiForgeryToken]
public ActionResult Index(Presenter model)
{
int pageNumber = (id ?? 1);
if (ModelState.IsValid)
{
using(var connection = new Context())
{
model.Tasks = connection.Tasks
.Where(task => task.Status == 5)
.ToPagedList(pageNumber, 30);
}
}
return View(model);
}
Esto también funciona bien a menos que el usuario haya cambiado la página, entonces los filtros son resto.
Así es como se ve mi clase de presentación
public class Presenter
{
public IPagedList<Task> Tasks { get; set; }
public TasksFiltersViewModel Form { get; set; }
public int PageNumber { get; set; }
public IEnumerable<SelectListItem> Statuses { get; set; }
}
¿Cómo puedo permitir que los usuarios usen las páginas mientras mantienen los filtros?
Aquí está mi VM de filtros
public class TasksFiltersViewModel
{
public int Status { get; set; }
}
La vista se ve así
@using (Html.BeginForm("Index", "Tasks", FormMethod.Post, new { @class = "form-horizontal" }))
{
@Html.AntiForgeryToken()
<div class="form-group">
@Html.LabelFor(m => m.Form.Status, new { @class = "control-label col-sm-3" })
<div class="col-sm-9">
@Html.DropDownListFor(m => m.Form.Status, Model.Statuses, new { @class = "form-control" })
@Html.ValidationMessageFor(m => m.Form.Status, "", new { @class = "text-danger" })
</div>
</div>
<div class="row">
<div class="col-sm-9 col-md-push-3">
<div>
<button type="submit" class="btn btn-default">Filter</button>
</div>
</div>
</div>
}
foreach (var task in Model.Tasks)
{
<tr>
<td>@task.Name</td>
<td>@task.Type</td>
<td>@Html.ActionLink("Edit", "Details", "Task", new { @id = task.Id }, new { @class = "btn btn-primary btn-sm" })</td>
</tr>
}
@Html.PagedListPager(Model.Tasks, id => Url.Action("Index", new { id }))
Dos formas de hacer esto.
La forma rápida: las cookies.
Simplemente configure una cookie para las opciones de filtro.
En las acciones donde se requiere filtrado, todo lo que necesita hacer es leer las cookies y filtrar en consecuencia.
No me gustan las cookies y las sesiones, y las evitaría.
Pero a veces puede ser lo que necesitas.
Usar parámetros GET
En su ejemplo, ha utilizado
POST
para filtrar.
Cada vez que hace clic en un enlace, se activa una solicitud
GET
, no una
POST
.
Entonces el filtrado no sucede.
La parte difícil es asegurarse de que los parámetros
GET
estén establecidos cada vez.
Podría crear una extensión personalizada similar a
Html.Action()
para comenzar.
Si va a verificar las opciones de filtro en varias acciones, considere usar un
Filter
acción.
Su formulario debe volver a publicarse en el método GET, y ese método debe incluir parámetros para sus propiedades de filtro.
El código de
PagedListPager
en la vista también debe incluir esas propiedades de filtro para que se conserven cuando navega a la página siguiente / anterior.
Tenga en cuenta que el método POST
Index()
no se utiliza y puede eliminarse.
Hacer que su modelo contenga un objeto complejo para las propiedades del filtro y una complejidad adicional al vincular, así que comience cambiando su modelo a
public class Presenter
{
public IPagedList<Task> Tasks { get; set; }
public int? Status { get; set; } // note nullable
... // add any other properties of TasksFiltersViewModel
public int PageNumber { get; set; }
public IEnumerable<SelectListItem> Statuses { get; set; }
}
Luego cambie el método
Index()
a
public ActionResult Index(int? id, int? status) // add any other parameters your filtering on
{
int pageNumber = (id ?? 1);
var tasks = db.Tasks; // IQueryable<Task>
if (status.HasValue)
{
tasks = tasks.Where(x => x.Status == status.Value)
}
if (otherParametersHaveValue)
{
tasks = tasks.Where(....);
}
Presenter model = new Presenter()
{
PageNumber = id ?? 1,
Status = status,
.... // set any other filter properties from the parameters
Statuses = new SelectList(...),
Tasks = tasks.ToPagedList(pageNumber, 30)
};
return View(model );
}
y cambia la vista a
// Make the form a GET
@using (Html.BeginForm("Index", "Tasks", FormMethod.Get, new { @class = "form-horizontal" }))
{
....
// Modify expression based on revised model properties
@Html.DropDownListFor(m => m.Status, Model.Statuses, ...)
}
....
// Add filter parameters to url so they are retained
@Html.PagedListPager(Model.Tasks, id => Url.Action("Index", new { id, status = Model.Status })) // add other filter properties as required