Introducción
En este ejemplo se editaran ordenes de compra pero sin hacer uso alguno de eventos de asp.net, se hará uso de una serie de librerías jquery que ayudaran en el proceso
Solo el botón de filtro y la paginación del gridview conservarán los eventos de asp.net, la edición de la entidad será completamente sin hacer uso de eventos.
Para esto se usara:
- jquery UI dialog
- jquery autocomplete
- jtemplates
- momentjs
Implementando jQuery Autocomplete
La implementación se encuentra en el archivo autocomplete.js del proyecto, en este simplemente se define
$(function () { $("[id*='txtCustomer']").autocomplete({ source: function (request, response) { var params = new Object(); params.companyName = request.term; $.ajax({ type: "POST", contentType: "application/json; charset=utf-8", url: "Default.aspx/GetCustomerList", data: JSON.stringify(params), dataType: "json", async: true, success: function (data) { response($.map(data.d, function (item) { return { label: item } })) }, error: function (request, status, error) { alert(jQuery.parseJSON(request.responseText).Message); } }); }, open: function (event, ui) { $(this).autocomplete("widget").css({ "width": 200, "font-size": 12 }); }, select: function (event, ui) { $("[id*='txtCustomer']").val(ui.item.label); } }); });
Como puede observarse invoca a un WebMethod implementado en el código de la pagina
[WebMethod] public static string[] GetCustomerList(string companyName) { string[] list = CustomerRepository.GetCustomer(companyName) .Select(x => x.CompanyName) .ToArray(); return list; }
Es importante resaltar el uso de una sección de estilo que permite definir el scroll del desplegable
<style type="text/css"> .ui-autocomplete { max-height: 200px; overflow-y: auto; /* prevent horizontal scrollbar */ overflow-x: hidden; /* add padding to account for vertical scrollbar */ padding-right: 20px; } </style>
Implementando Edición GridView
La edición en el control GridView tiene algunos detalles interesantes para el análisis. la selección se implementa por medio de un simple template conteniendo el tag de html de imagen al cual se le asocia un atributo para identificar el id de la orden que define
Este atributo será luego usado por el evento de la imagen cuando hace $(this).attr(“idorder”)
function RegisterEditOrderEvent() { $("[id*='gvOrders'] [id*='imgeditorder']").click(function () { var orderId = $(this).attr("idorder"); $('#popuporderedit').dialog({ title: 'Edicion Orden Nro: ' + orderId }); $('#popuporderedit').data('orderId', orderId); $('#popuporderedit').dialog('open'); }); }
Nota: hay que remarcar como se asigna el id de la orden al dialogo, usando el .data(), usado luego para saber que id esta mostrando el popup
Se observara también que este evento no esta en el clásico $(function(){… para que se cargue cuando la pagina este disponible, sino que es invocado puntualmente ante determinados eventos.
Esto es necesario porque el gridview sigue conservando los eventos de asp.net, y el postback que estos causando quitan las asociaciones de los eventos de jquery adjunta a los controles, a pesar de usar UpdatePanel estos eventos aun existen, por eso se usa al final de cada acción el ScriptManager.RegisterStartupScript() para que vuelva a lanzar la ejecución y rebindear el evento click
protected void gvOrders_PageIndexChanging(object sender, GridViewPageEventArgs e) { gvOrders.PageIndex = e.NewPageIndex; LoadGridOrder(); ScriptManager.RegisterStartupScript(Page, typeof(Page), "registerorderevent", "RegisterEditOrderEvent();", true); } protected void btnFiltrar_Click(object sender, EventArgs e) { LoadGridOrder(); ScriptManager.RegisterStartupScript(Page, typeof(Page), "registerorderevent", "RegisterEditOrderEvent();", true); }
Edición usando jQuery UI Dialog
La definición es bastante simple, lo que quizás sea complejo es la carga y actualización de los campos de la entidad
$('#popuporderedit').dialog({ autoOpen: false, modal: true, resizable: false, width: 500, heigth: 250, title: 'Edicion Orden Nro:', open: function (event, ui) { initialize(); loadOrder($(this).data('orderId')); }, close: function (event, ui) { //limpia todos los textbox del popup $('#popuporderedit :text').val(''); }, buttons: { Actualizar: function () { updateOrder(); }, Cancel: function () { $(this).dialog("close"); } } });
Jquery UI Dialog – Carga controles
La carga de los datos en el popup tiene dos momentos, una de inicialización y otra de asignación de los datos de la entidad que se edita
En este caso la inicialización mas que nada implica cargar los combo
function initialize() { loadComboBox('ddlCustomer', 'GetAllCustomer'); loadComboBox('ddlEmployeer', 'GetAllEmploye'); loadComboBox('ddlShipVia', 'GetAllShipper'); } function loadComboBox(comboname, webmethodname) { var template = "{#foreach $T as record}\ <option value='{$T.record.id}'>{$T.record.name}</option>\ {#/for}"; var combo = $('#' + comboname); $.ajax({ type: "POST", contentType: "application/json; charset=utf-8", url: "Default.aspx/" + webmethodname, data: '{}', dataType: "json", async: true, success: function (data) { //combo.setTemplate($("#SelectTemplate").html()); combo.setTemplate(template); combo.processTemplate(JSON.parse(data.d)); }, error: function (request, status, error) { alert(JSON.parse(request.responseText).Message); } }); }
Es importante notar como se hace uso de jtemplate para definir el <option> de combo. El témplate puede ser definido tanto en una variable, o si este es algo mas complejo podría hacerse en una sección del html
<script type="text/html" id="SelectTemplate"> {#foreach $T as record} <option value="{$T.record.id}">{$T.record.name;}</option> {#/for} </script>
Para que se puede recuperar la info será necesario contar con los webmethod
[WebMethod] public static string GetAllCustomer() { var list = CustomerRepository.GetAllCustomer() .Select(x => new { id = x.CustomerID, name = x.CompanyName }); return JsonConvert.SerializeObject(list); } [WebMethod] public static string GetAllEmploye() { var list = EmployeRepository.GetAllEmploye() .Select(x => new { id = x.EmployeeID, name = x.FullName }); return JsonConvert.SerializeObject(list); } [WebMethod] public static string GetAllShipper() { var list = ShipperRepository.GetAllShipper() .Select(x => new { id = x.ShipperID, name = x.CompanyName }); return JsonConvert.SerializeObject(list); }
Se hace uso de la librería JSON.Net para serializar el objeto anónimo
Para cargar la orden se usa una técnica similar
function loadOrder(orderId) { var params = new Object(); params.orderId = orderId; $.ajax({ type: "POST", contentType: "application/json; charset=utf-8", url: "Default.aspx/GetOrder", data: JSON.stringify(params), dataType: "json", async: true, success: function (data) { var order = JSON.parse(data.d); $('#ddlCustomer').val(order.CustomerID); $('#ddlEmployeer').val(order.EmployeeID); $('#txtOrderDate').val(order.OrderDate); $('#txtRequiredDate').val(order.RequiredDate); $('#txtShippedDate').val(order.ShippedDate); $('#ddlShipVia').val(order.ShipVia); $('#txtFreight').val(order.Freight); $('#txtShipName').val(order.ShipName); $('#txtShipAddress').val(order.ShipAddress); $('#txtShipCity').val(order.ShipCity); $('#txtShipRegion').val(order.ShipRegion); $('#txtShipPostalCode').val(order.ShipPostalCode); $('#txtShipCountry').val(order.ShipCountry); }, error: function (request, status, error) { alert(JSON.parse(request.responseText).Message); } }); }
Definiendo el webmethod que envía los datos de la orden
[WebMethod] public static string GetOrder(int orderId) { var order = OrderRepository.GetOrderById(orderId); return JsonConvert.SerializeObject(new { OrderID = order.OrderID, CustomerID = order.CustomerID, EmployeeID = order.EmployeeID, OrderDate = order.OrderDate.ToShortDateString(), RequiredDate = order.RequiredDate.ToShortDateString(), ShippedDate = order.ShippedDate.HasValue ? order.ShippedDate.Value.ToShortDateString() : "", ShipVia = order.ShipVia, Freight = order.Freight, ShipName = order.ShipName, ShipAddress = order.ShipAddress, ShipCity = order.ShipCity, ShipRegion = order.ShipRegion, ShipPostalCode = order.ShipPostalCode, ShipCountry = order.ShipCountry }); }
Fue necesario redefinir la entidad que se envía y no directo la entidad Order ya que de no hacerse se obtiene un error de referencia circular, causado por las entidades asociadas en Entity Framework
Jquery UI Dialog – Actualización
Actualizar la entidad implica crear un objeto javascript que represente la entidad, lo bueno es que JSON.stringify() lo hace muy fácil, mapeando la entidad directamente
function updateOrder() { var order = new Object(); order.OrderID = $('#popuporderedit').data('orderId'); order.CustomerID = $('#ddlCustomer').val(); order.EmployeeID = $('#ddlEmployeer').val(); order.OrderDate = moment($('#txtOrderDate').val(), "DD/MM/YYYY").toDate(); order.RequiredDate = moment($('#txtRequiredDate').val(), "DD/MM/YYYY").toDate(); var shippedDate = moment($('#txtShippedDate').val(), "DD/MM/YYYY"); order.ShippedDate = shippedDate == null ? null : shippedDate.toDate(); order.ShipVia = $('#ddlShipVia').val(); order.Freight = $('#txtFreight').val(); order.ShipName = $('#txtShipName').val(); order.ShipAddress = $('#txtShipAddress').val(); order.ShipCity = $('#txtShipCity').val(); order.ShipRegion = $('#txtShipRegion').val(); order.ShipPostalCode = $('#txtShipPostalCode').val(); order.ShipCountry = $('#txtShipCountry').val(); var params = new Object(); params.order = order; $.ajax({ type: "POST", contentType: "application/json; charset=utf-8", url: "Default.aspx/ActualizarOrder", data: JSON.stringify(params), dataType: "json", async: true, success: function (data) { alert('Actualizacion Correcta'); $('#popuporderedit').dialog("close"); }, error: function (request, status, error) { alert(JSON.parse(request.responseText).Message); } }); }
El único inconveniente fue con las fechas, al encontrarse en formato dd/MM/yyyy esta no era reconocida por javascript, es por eso que con ayuda de momentjs se logro cambiar de formato a una fecha correcta
Código
Para el ejemplo se hace uso de Visual Studio 21010, la base de datos es Sql Compract 3.5
[C#]
|