Saltar al contenido

Artículos, tutoriales, trucos, curiosidades, reflexiones y links sobre programación web ASP.NET Core, MVC, Blazor, SignalR, Entity Framework, C#, Azure, Javascript... y lo que venga ;)

17 años online

el blog de José M. Aguilar

Inicio El autor Contactar

Artículos, tutoriales, trucos, curiosidades, reflexiones y links sobre programación web
ASP.NET Core, MVC, Blazor, SignalR, Entity Framework, C#, Azure, Javascript...

¡Microsoft MVP!
martes, 24 de noviembre de 2009

En un post anterior dedicado a jqGrid y ASP.NET MVC vimos lo sencillo que resultaba implementar un potente grid para mostrar datos tabulares, permitiendo paginación, ordenación y redimensionado de columnas.

Pero, como ya comenté entonces, jqGrid es mucho más que eso. En este artículo estudiaremos la implementación de la funcionalidad de borrado de filas integrada en el propio componente, utilizando intercambio de datos Ajax con el lado servidor para actualizar el modelo.

Partiremos del ejemplo que desarrollamos anteriormente, y nos centraremos únicamente en introducir los cambios necesarios para introducir esta nueva capacidad. También, como en el caso anterior, encontraréis al final un enlace al proyecto de demostración, para Visual Web Developer Express 2008 SP1 y ASP.NET MVC 1.0.

1. Preparamos la infraestructura

Selección de módulos en jqGridAntes de nada, y es algo que es importante recordar cuando trabajemos con jqGrid, debemos pensar qué módulos de este componente necesitamos en nuestro proyecto.

En el post anterior descargamos exclusivamente los necesarios para implementar la visualización del grid; ahora, dado que vamos a utilizar más funcionalidades del componente, debemos seleccionar en la herramienta de descarga aquellos que nos harán falta, el base y los relativos a la edición de datos.

En teoría deberíamos seleccionar los módulos estrictamente necesarios para nuestros fines, pero en la práctica no es fácil adivinar cuál de ellos implementa justamente lo que estamos buscando. De hecho, es bastante frecuente encontrarse con errores de script cuando no acertamos con el módulo exacto, al que siguen bastantes iteraciones prueba-error hasta que conseguimos averiguar cuál debemos indicar en la descarga.

Por eso en este caso, seleccionaremos todos los módulos relativos a la edición; eso nos permitirá, además, seguir implementando funcionalidades como el alta o la modificación sin tener que volver a descargar componentes.

Aparte de los módulos a incluir en la descarga, el resto de los pasos de preparación de la infraestructura son idénticos a los descritos en los puntos 1 al 3 del post inicial:

  • Copiar los archivos de script (jqGrid y el archivo de localización) en el proyecto.
  • Descargar el tema visual de jQuery UI y añadirlo al proyecto.
  • referenciar las librerías de scripts y estilos en la master (o vistas donde vayamos a usarlo).

2. El modelo

Vamos a ampliar la clase GestorDeAmigos anterior para que sea capaz de emular el almacenamiento en una base de datos, pero utilizando como soporte una colección en memoria que haremos persistir en una variable de aplicación. Además, aprovecharemos para añadirle un método Delete() que nos permita eliminar del almacén la persona cuyo “Id” le pasemos como parámetro.

public bool Delete(int id)
{
    Amigo amigo = DatosAmigos.FirstOrDefault(a => a.Id == id);
    if (amigo == null)
        return false;
 
    DatosAmigos.Remove(amigo);
    return true;
}
 
No profundizaré más en el modelo, pues el código es de lo más convencional. El que tenga curiosidad por ver cómo se implementa el almacén en una variable de aplicación, que acuda al fuente del proyecto de demostración.

3. La vista

En la vista debemos hacer muy pocos ajustes para permitir la eliminación de los datos. Básicamente, tendremos que habilitar un panel de botones en el grid, indicar que deseamos que aparezca el botón de eliminación, y configurar el comportamiento de éste, para lo cual invocaremos al método navGrid() después de la llamada de inicialización del grid que ya vimos el otro día:

<script type="text/javascript">
    jQuery(document).ready(function() {
    
        jQuery("#list").jqGrid({
            [...] // OMITIDO. Idéntico al del post anterior.
        });
 
        $("#list").navGrid(
                null,
                { refresh: true, add: false, edit: false, del: true, search: false },
                null, // parámetros para el alta
                null, // parámetros para la edición
                {     // parámetros para la eliminación
                    url: '<%= Url.Action("Eliminar") %>',
                    width: 500,
                    afterSubmit: function(r, d) {
                        return [r.responseText=="", r.responseText];
                    }
                }
        );
});

Los parámetros que estamos pasando al método navGrid() son los siguientes:

  • el primer parámetro debería ser jQuery('#pager'), que es la referencia hacia el control de paginación que estamos utilizando. En este caso es un nulo porque esta referencia se incluyó en la inicialización de jqGrid.
  • A continuación, creamos un objeto anónimo en el que establecemos a true las propiedades del y refresh, que indica que queremos mostrar los botones de eliminación y recarga de datos. El resto de propiedades predefinidas, add, edit, y search, equivalentes a los botones de añadir, editar y buscar registros, respectivamente, las establecemos a false con objeto de que no aparezcan botones para invocarlas; ya las activaremos en otros posts ;-)
  • el siguiente parámetro se trata de un objeto donde configuramos el comportamiento del botón de alta de registros. Dado que no vamos a implementarlo ahora, lo establecemos a nulo.
  • el cuarto parámetro es lo mismo que el anterior, pero para configurar la edición, por lo que también se encuentra establecido a null.
  • a continuación, y por último, el objeto en cuyas propiedades definimos el comportamiento del botón de eliminación:

    • La URL a la acción que se invocará en servidor, que la obtenemos utilizando el UrlHelper de MVC. En este caso, invocaremos a una acción llamada “Eliminar”, a la que el sistema enviará el Id del registro activo.
    • El ancho del cuadro de diálogo de confirmación.
    • En afterSubmit implementamos una función callback que jqGrid llamará cuando haya recibido el resultado de la petición Ajax. El primer parámetro que nos envía es el objeto XMLHttpRequest donde encontraremos la respuesta obtenida desde el servidor; el segundo parámetro contiene los datos que han sido enviados a la petición.

      El retorno de la función callback debe ser siempre un array con dos elementos. El primero es un booleano indicando si la eliminación ha tenido éxito, y el segundo es el mensaje de error, en caso de que se haya producido:

      return [ exito , "mensaje de error" ];

      Es importante ahora resaltar una cosa: salvo los parámetros de entrada y el tipo de retorno descritos anteriormente, jqGrid no nos impone ninguna particularidad más respecto a cómo debemos implementar este método, el tipo de información que recibiremos desde el controlador o cómo la procesaremos al recibirla. Somos totalmente libres de elegir la forma en la que haremos las cosas.

      En nuestro caso, vamos a hacer una implementación muy simple en base a la siguiente convención: el controlador retornará un string con una descripción del error en caso de que se produzca algún problema borrando el registro, y retornará un nulo cuando todo vaya bien. Esto nos permite implementar el callback utilizando la siguiente expresión:
      return [r.responseText=="", r.responseText];

      Si observáis, estamos llenando el array de retorno de tal forma que el primer parámetro será cierto si la respuesta obtenida está vacía (o sea, no hay error), y en el segundo parámetro introducimos la respuesta tal cual la hemos obtenido del servidor.

4. El controlador

Dado que la lógica la tenemos implementada en el modelo, y que la vista ya está preparada para ponerse en contacto con el controlador vía Ajax y para recibir el feedback sobre el éxito de la operación, sólo nos queda implementar muy rápidamente el método de acción:

public ActionResult Eliminar(int id)
{
    if (!gestorDeAmigos.Delete(id))
        return Content("Error eliminando el registro");
 
    return null;
}

Podréis observar que si se produce un error, retornamos un ContentResult describiendo el problema; en otros casos, devolvemos un nulo.

Para probar el funcionamiento de una eliminación errónea podéis, por ejemplo, abrir dos navegadores contra la aplicación, borrar un registro desde uno de ellos e intentar borrarlo también desde el otro.

Y… ¡Voilá!

Una vez habiendo implementado el modelo, la vista y el controlador, sólo nos queda probar la aplicación, que veremos que funciona perfectamente ;-P

jqGrid+ASP.NET MVC en acción

Resumiendo, en este post hemos seguido profundizando en las capacidades de jqGrid, implementando paso a paso la funcionalidad de eliminación de registros. Hemos podido observar también el escaso código (¡a pesar de la longitud del post!) que hay que añadir para disponer de esta funcionalidad, y de lo sencillo y reutilizable que resulta su implementación.

Descargar proyecto de demostración:

Publicado en: Variable not found.

19 Comentarios:

Anónimo dijo...

Muy buen post, me resulto util.

Quisiera saber como seria para editar multiples registros.. osea en el jqgrid activar el multiselect y poder editar varios registros a la vez

cugartemendia dijo...

Hola , muchas gracias por tu blog.

Tengo una duda en esta parte, r y d quines son , y el return para donde va.
Gracias


afterSubmit: function(r, d) { return [r.responseText=="", r.responseText

josé M. Aguilar dijo...

Hola, gracias por comentar!

@cugartemendia, "r" es el objeto XMLHttpRequest donde encontraremos la respuesta obtenida desde el servidor; "d" contiene los datos que han sido enviados a la petición (el id).

El return devuelve el control a jqGrid. El return [e,m] lo que hace es que se muestre el mensaje de error "m" si el valor de "e" es cierto.

Espero que te quede más claro ahora.

Un saludo.

josé M. Aguilar dijo...

@anonimo, lo único que debes hacer es añadir la siguiente propiedad a jqGrid:

...
pager: jQuery('#pager'),
rowNum: 20,
multiselect: true, <- Ésta
rowList: [20, 50, 100],
sortname: 'Apellidos',
sortorder: 'asc',
viewrecords: true,
...
En el controlador, la única diferencia es que recibirás el parámetro "id" como string, conteniendo los ids de las filas a eliminar separados por comas.

Saludos.

HeGer dijo...

Hola
me gustó mucho ésta y la otra guía, pero me costo un poco hacerla correr sobre IIS 5.1, hay un detalle con las referencias, por ejemplo:

Si tienes

<script src="../../Scripts/jquery-1.2.6.js" type="text/javascript"></script>

se tiene que sustituir por

<script src="<%= Url.Content("~/Scripts/jquery-1.3.2.min.js") %>" type="text/javascript"></script>

eso es un detalle si se quiere utilizar MVC en XP con IIS 5.1

ésto lo saque de aquí

Unknown dijo...

Gracias por el post.

Este jqGrid esta muy bueno.

E visto que se puede manejar adicionar,editar,buscar en la misma grilla.
Seria muy complicado implementarlos?
Tienes informacion acerca de esto?

josé M. Aguilar dijo...

@jose, puedes encontrar mucha información en la documentación del componente.

Saludos.

Anónimo dijo...

hola.

Tengo un problema con jqgrid, me gustaría poder eliminar el grid por completo y no encuentro la manera de hacerlo.
¿Alguien conoce la manera?

josé M. Aguilar dijo...

Hola,

si te refieres a eliminar todas las filas de un grid, podrías habilitar la selección múltiple.

En la documentación del componente (http://www.trirand.com/jqgridwiki/doku.php?id=wiki%3Aoptions) verás que hay una propiedad multiselect que te permite hacerlo.

También podrías hacerlo de forma manual y externa a jqgrid, introduciendo un botón que invoque a una acción en el servidor que los elimine.

Saludos.

Anónimo dijo...

Hola gente, a ver si alguien pueden ayudarme con lo siguiente:
Estoy trabajando con C# en ASP Net y mi idea es usar una grilla JQGrid de modo tal que al seleccionar una fila, capture el ID del registro seleccionado para luego ser procesado por una Web Form frmDetalle.aspx.
Por ejemplo, la lista JQGrid me muestra y para ver el detalle de una persona en particular lo selecciono, capturo el ID con: onSelectRow: function(ids) {…} y le pase el ID a un método de la clase frmDetalle.aspx.cs.
Mi duda es como capturo el ID del registro seleccionado en la grilla JQGrid dentro de la clase frmDetalle.aspx.cs . O sea no tengo forma de pasar parámetros entre lo que veo en la grilla y lo que tengo en mis clases aspx.cs.
Por favor si alguien tiene código de la función onSelectRow: function(ids) {…} y del método que iría en la clase aspx.cs para capturar el ID seleccionado. Desde ya muchas gracias.

josé M. Aguilar dijo...

Hola, @anonimo.

He respondido tu cuestión en el foro de ASP.NET MVC.

Saludos.

Fernando dijo...

Muchas Gracias!! ahora veo la respuesta...

triplear.com.ar dijo...

Buenas !! les paso un problema que tengo con una grilla en jqgrid.
Tengo dos grillas, una master/detail, ejemplo master: grupo de alumnos
y detail: alumnos

En la grilla de alumnos tengo habilitada la opcion de multiselect.

** Cuando yo ejecuto la accion de borrar seleccionando varios
registros se envia por metodo GET los ids de los alumnos separados por
coma ejemplo 22,33,55,122 etc con lo cual me elimina los
seleccionados.

** Pero cuando hago EDICION solo me envia el primer ids de la
seleccion ejemplo: 22 Esto lo necesito para ejemplo cambiar todos los
alumnos seleccionados a un determinado grupo!!

Alguien sabe porque puede suceder esto, como lo puedo resolver ?


Saludos
Ramiro

Anónimo dijo...

Esta muy bueno el Blog, pero aún no entiendo com puedo hacer para ingresar un dato :( favor su ayuda e tratado, pero no se que devo poner para que cuandodo lebante le pupap muestre mis datos a ingresar, favor su ayuda estoy con mi tesis y quiero usar esta grilla

josé M. Aguilar dijo...

Hola!

En este hilo de los foros de MSDN daba indicaciones sobre cómo realizar la edición e inserción de datos:

http://social.msdn.microsoft.com/Forums/es-ES/aspnetmvces/thread/287e16c4-8f8f-4689-a6be-ffd03e2a2d8b

Espero que te sea de ayuda.

Saludos.

Gabriel dijo...

Como puedo hacer que al editar una fila me cargue un combo, pero ese combo se cargue desde la BD ??.

Favor su atuda si tienen un ejemplo con mvc

josé M. Aguilar dijo...

Hola, Gabriel.

Puedes ver una demo y su código en la web oficial de jqgrid, en http://www.trirand.com/blog/jqgrid/jqgrid.html.

Selecciona en el menú izquierdo "Row editing > Input types" y ahí lo tienes ;-)

Saludos.

Anónimo dijo...

José como estas :) gracias por contestar, si revise eso,pero el problema es que lo carga en dura :{value:"FE:FedEx;IN:InTime;TN:TNT;AR:ARAMEX"}},

Yo tengo lo siguiente :
<--en jqgrid tengo -->
{ name: 'Usuario', index: 'Usuario', width: 300, align: 'left', editable: true, edittype: 'select', editoptions: { value: cargar_paises()} },



Luego tengo la siguiente funcion :
function cargar_paises() {
var url = '<%= Url.Action("ListUsuarios", "AsignacionUsuario") %>';
var option = "0:Seleccione";

$.post(url, function (data) {

if (data != null) {
$.each(data,
function (id, objeto) {
option = option + ";" + objeto.value + ":" + objeto.name;
return option;

});
}
}
)

return option;


}

<-- Mi controler es -->

public JsonResult ListUsuarios()
{

var data = new object[] { };




data = new object[] {
new { value = 1, name = "Los pilares de la tierra" },
new { value = 2, name = "La catedral del mar" },
new { value = 3, name = "mmaulen" }
};



return Json(data);
}

Mi idea era cargar de esa forma, pero no funciona.

josé M. Aguilar dijo...

Bueno, siempre podrías renderizar directamenta la lista, no?

Es decir, al componer la vista, la expresión {value:"FE:FedEx;IN:InTime;TN:TNT;AR:ARAMEX"} podrías generarla directamente con la información enviada por el controlador.

Es decir, desde el controlador envías la colección de elementos a la vista, y en el momento de renderizar generas esta cadena con los textos y códigos separados por punto y coma.

//script:
var datos = { value: '<%= generar()%>' };

// código en la vista o en un helper:
public string generar()
{
StringBuilder sb = new ...;
foreach(var el in Model.Elementos)
{
sb.Append(el.Codigo);
sb.Append(":");
sb.Append(el.Nombre);
sb.Append(";");
}
return sb.ToString();
}


(El código está hecho al vuelo, sin probarlo, por lo que es posible que tenga errores, pero creo que te valdrá para pillar la idea de lo que te comento).

Saludos.