Sie sind auf Seite 1von 5

ASP.

NET MVC: WebGrid con filtro, paginacin y


ordenacin
El problema fundamental es que WebGrid no incorpora ningn tipo de ayuda para
realizar esta tarea tan frecuente; simplemente se encarga de mostrar los datos que le
suministremos, por lo que si queremos filtrarlos debemos hacerlo de forma manual.

Partiendo del proyecto que desarrollamos en el ltimo post de la serie vamos a ver cmo
podemos aadir al grid un par de criterios de bsqueda, de forma que el resultado luzca
tal que as:

El campo Texto nos permitir buscar subcadenas en el nombre y apellidos de las


personas almacenadas en la base de datos, y los otros dos campos permitirn filtrar por
rango (mn-mx) los hijos que tienen. Como es habitual, estas condiciones las
combinaremos con un Y lgico.

1. La vista

En primer lugar introducimos en la vista, justo antes de generar el grid, el formulario


que utilizaremos para solicitar al usuario los criterios de bsqueda:
El cdigo es el siguiente:

@using(Html.BeginForm(null, null, FormMethod.Get))


{
<fieldset>
<legend>Criterios de bsqueda</legend>
@Html.Label("buscar", "Texto:")
@Html.TextBox("buscar")
@Html.Label("hijosMin", "Hijos mn:")
@Html.TextBox("minHijos")
@Html.Label("maxHijos", "Hijos mx:")
@Html.TextBox("maxHijos" )

<input type="submit" value="Buscar" />


</fieldset>
}

Observad la simplicidad del formulario. Por no usar, no usa ni siquiera la sintaxis


lambda en los helpers de edicin. Los controles vamos generarlos partiendo de campos
cuyos valores existirn en el query string, y no desde el Modelo, que es lo habitual, y
por esta razn fijaos que el formulario est configurado para ser enviado utilizando el
mtodo HTTP GET.

De esta forma podemos propagar muy fcilmente el valor de los controles (textbox)
entre las llamadas:

si el usuario introduce criterios y pulsa el botn enviar, la URL a la que se


realizar la peticin ser, por ejemplo,
/personas/index?buscar=aguilar&hijosMin=0&hijosMax=8.
si el usuario utiliza los botones de navegacin propios del grid (avance/retroceso
de pgina, salto a pgina directa, o reordenacin), estos parmetros sern
aadidos a los anteriores, de forma que seguirn manteniendo sus valores entre
las distintas llamadas. Esto es as gracias a que Webgrid genera los enlaces de
estas acciones respetando los parmetros actuales del query string; es decir, si
estamos filtrando y saltamos a la pgina 4, accederemos a una direccin que
incluir tanto la informacin de los criterios de bsqueda como la de paginacin,
algo como:
/personas/index?buscar=aguilar&minHijos=0&maxHijos=8&page=4.

Y con esto, dejamos completada la capa vista.

2. El Controlador

Si recordis, el mtodo de accin encargado de obtener los datos de grid y enviar la


vista con los datos al usuario reciba tres parmetros: la pgina actual, el campo de
ordenacin y el sentido de sta (ascendente/descendente).

Dado que ahora necesitar tambin obtener los criterios de ordenacin, debemos
ampliar su definicin aadiendo parmetros para estos valores:

public ActionResult Index(int page = 1, string sort = "Apellidos", string


sortDir = "ASC",
string buscar = null, int? minHijos = null, int?
maxHijos = null)

Observad que son todos parmetros opcionales, y los establecemos a nulo para detectar
fcilmente cundo nos vienen rellenos.

Y en qu puntos necesitamos utilizar estos nuevos parmetros? Pues slo en dos:

en la llamada que hacemos al Modelo para contar el total de filas del grid, a la
que tendremos que informar sobre los criterios de filtrado para que el conteo se
realice correctamente.
en la llamada que hacemos al Modelo para obtener las filas a mostrar en la
pgina actual, donde obviamente tambin deberemos tener en cuenta los filtros.

La accin quedara ms o menos as:

public ActionResult Index(int page = 1, string sort = "Apellidos", string


sortDir = "ASC",
string buscar = null, int? minHijos = null, int?
maxHijos = null)
{
var numPersonas = _services.ContarPersonas(buscar, minHijos, maxHijos);
var personas = _services.ObtenerPaginaDePersonasFiltrada(page,
PERSONAS_POR_PAGINA,
sort, sortDir, buscar, minHijos,
maxHijos);

var datos = new PaginaDePersonasViewModel()


{
NumeroDePersonas = numPersonas,
PersonasPorPagina = PERSONAS_POR_PAGINA,
Personas = personas
};

return View(datos);
}

Y esto es todo en el controlador.

3. El Modelo

Y por ltimo, ya en el Modelo, debemos hacer que los mtodos utilizados desde el
controlador (ContarPersonas y ObtenerPaginaDePersonasFiltrada) tengan en
cuenta los parmetros en los que indicamos las condiciones de bsqueda.

En el primero de ellos, simplemente retornamos el nmero de personas que cumplan los


criterios que nos llegan como parmetros:
public int ContarPersonas(string textoBuscar = null, int? minHijos = null,
int?
maxHijos = null)
{
IQueryable<Persona> query = _datos.Personas;
query = queryPersonasFiltrada(textoBuscar, minHijos, maxHijos, query);
return query.Count();
}

El mtodo de utilidad queryPersonasFiltrada() que estamos utilizando nicamente


se encarga de aadir a la query las clusulas where que necesitamos para tener en
cuenta las condiciones especificadas:

private static IQueryable<Persona> queryPersonasFiltrada(string textoBuscar,


int? minHijos,
int? maxHijos, IQueryable<Persona>
query)
{
if (!string.IsNullOrWhiteSpace(textoBuscar))
query = query.Where(p => p.Nombre.Contains(textoBuscar) ||
p.Apellidos.Contains(textoBuscar));
if (maxHijos != null)
query = query.Where(p => p.NumeroDeHijos <= maxHijos);
if (minHijos != null)
query = query.Where(p => p.NumeroDeHijos >= minHijos);
return query;
}

Por ltimo, implementamos el mtodo que obtiene los datos a mostrar en la pgina
actual:

public IEnumerable<Persona> ObtenerPaginaDePersonasFiltrada(int paginaActual,


int personasPorPagina,
string columnaOrdenacion, string sentidoOrdenacion,
string textoBuscar, int? minHijos, int? maxHijos)
{
// Comprobamos los datos de entrada
sentidoOrdenacion = sentidoOrdenacion.Equals("desc",
StringComparison.CurrentCultureIgnoreCase) ?
sentidoOrdenacion : "asc";

var validColumns = new[] { "apellidos", "fechanacimiento", "email",


"numerodehijos" };
if (!validColumns.Contains(columnaOrdenacion.ToLower()))
columnaOrdenacion = "apellidos";

if (paginaActual < 1) paginaActual = 1;


if (personasPorPagina < 1) personasPorPagina = 10;

// Generamos la consulta
var query = (IQueryable<Persona>) _datos.Personas
.OrderBy("it." + columnaOrdenacion + " " +
sentidoOrdenacion);

query = queryPersonasFiltrada(textoBuscar, minHijos, maxHijos, query);


return query
.Skip((paginaActual - 1) * personasPorPagina)
.Take(personasPorPagina)
.ToList();
}

Hay poco que comentar sobre este cdigo. En primer lugar se realiza una comprobacin
bsica de los parmetros de entrada, para a continuacin generar la consulta que se
realizar sobre la base de datos. Como podis observar, tambin se utiliza el mtodo
queryPersonasFiltrada() para aplicar los criterios de consulta.

Das könnte Ihnen auch gefallen