jquery - ejemplo - how to use ajax in asp net mvc
Vistas parciales vs. Json(o ambos) (4)
Aquí hay una manera de aprovechar el tipo de Content-Type
devuelto por cada resultado respectivo. Estamos utilizando esto para enviar información de error, y ya existe JS para mostrar los mensajes, por lo que obtenemos la vista parcial que deseamos o la información de control para el informe de errores, etc.
Para referencia, una vista parcial devuelve text/html
y una respuesta JSON debe devolver application/json
.
Como de costumbre, la parte divertida está en el lado de javascript, ¡y el JQuery ajax()
no decepciona aquí!
En su controlador, simplemente devuelva PartialView()
o Json(model,)
según corresponda; Lo estamos utilizando en formato de try/catch
.
public ActionResult Edit(int id) {
try {
var model = getYourModel();
return PartialView("Edit", model);
}
catch (Exception ex) {
var mi = new MessageInfo(MessageType.Error, String.Format("Edit failed: {0}", ex.Message), true);
return Json(mi, "application/json", JsonRequestBehavior.AllowGet);
}
}
En el lado de JS, estamos usando la siguiente función. Tenga en cuenta que necesita restablecer cualquier evento JQuery que haya conectado en $(document).ready()
desde el GET de nivel de página inicial, por lo que tenemos un parámetro de devolución de llamada.
function getPartialView(action, controller, model, divId, callback) {
var url = "/" + controller + "/" + action + "/";
$.ajax({
type: "GET",
url: url,
data: model,
success: function (data, textStatus, jqXHR) {
var ct = jqXHR.getResponseHeader("Content-Type");
var mx = ct.match("text//html");
if (mx != null) {
$(divId).html(data);
if (callback) {
callback($(divId));
}
}
else {
addMessage(data.type, data.title, data.text, data.sticky);
}
},
error: function (jqXHR, textStatus, errorThrown) {
addMessage(3, "/"" + url + "/": Failed", textStatus + ": " + errorThrown, false);
}
});
}
El único bit difícil es verificar el encabezado Content-Type
en la respuesta y comportarse en consecuencia. Tenga en cuenta que estamos "haciendo trampa" asumiendo que JSON no es HTML. Estamos llamando a nuestra función addMessage()
preexistente, ¡haga lo que necesite!
Y finalmente, aquí hay un ejemplo de elemento de anclaje con onclick
targeting getPartialView()
arriba.
<a href="#" onclick="getPartialView(''Action'', ''Controller'', model, ''#partialviewdivid'', function(dvx) { connectJqueryEvents(dvx); })">Cancel</a>
Funciona genial...
Excepto para los formularios Ajax.BeginForm()
través de Ajax.BeginForm()
donde la carga de JSON se trata erróneamente como HTML debido a una validación insuficiente de Content-Type
. El resultado es que a su div
se le agrega JSON, que básicamente no se procesa como HTML. La AjaxOptions.OnSuccess
llamada AjaxOptions.OnSuccess
ejecuta, ¡pero es demasiado tarde para su DOM en ese momento!
Hay una solución simple, pero desafortunadamente requiere una pequeña reparación a jquery-unobtrusive-ajax.js
porque la función asyncOnSuccess()
fue breve como estaba escrita.
function asyncOnSuccess(element, data, contentType) {
var mode;
if (contentType.indexOf("application/x-javascript") !== -1) {
return;
}
if (contentType.indexOf("application/json") !== -1) {
return;
}
...snip...
}
En la versión OOTB, falta la segunda instrucción if
; agregarlo es la solución necesaria para evitar que se estrelle su carga JSON en el DOM.
Con esta corrección en su lugar, la carga útil de JSON pasa a su AjaxOptions.OnSuccess
Javascript, y puede proceder según sea necesario.
Si puedes conseguir ambos
Es de esperar que, ya que está enviando a Json, puede enviar cualquier tipo de modelo y dejar que Javascript lo resuelva; hasOwnProperty()
es muy útil allí. Así que, obviamente, puede enviar alguna vista HTML a través de RenderViewToString()
ya mencionado.
Utilizo ASP.NET MVC con jQuery y tengo muchas solicitudes de Ajax para mis controladores.
Utilice Vistas parciales (usercontrols) para crear la vista inicial cuando se carga una página. Luego, si necesito agregar / reemplazar datos según mi solicitud de Ajax, compilo HTML a partir de la respuesta de Json.
Este enfoque me da el control total, es decir. Si algo salió mal, puedo recuperar información adicional de mi controlador y luego mostrar un mensaje de error basado en eso.
Sin embargo, recientemente he estado realmente molesto con todo el trabajo adicional que conlleva mantener la estructura HTML tanto en mis vistas parciales como en la parte que genera HTML a partir de Json.
Me gusta hacer una solicitud de jQuery ajax y luego hacer que el controlador devuelva PartialView ("mypartialview") y luego usar jQuery para reemplazar a HTML en la vista.
Sin embargo, de esta manera no puedo adjuntar datos adicionales desde el controlador (es lo que me da la vista parcial) o nada. Al menos esa es mi opinión actual.
Si alguna validación sale mal en algún punto de la acción de mi controlador, no quiero devolver el HTML de la vista parcial.
Entonces, ¿cómo vas sobre el manejo de este problema?
Gracias por leer.
Basándome en this respuesta de , me he propuesto hacer lo mismo.
Primero crea un método de extensión para la clase de controlador.
public static string RenderViewToString(this Controller controller, string viewName, object model)
{
using (var writer = new StringWriter())
{
var viewResult = ViewEngines.Engines.FindPartialView(controller.ControllerContext, viewName);
controller.ViewData.Model = model;
var viewCxt = new ViewContext(controller.ControllerContext, viewResult.View, controller.ViewData, controller.TempData, writer);
viewCxt.View.Render(viewCxt, writer);
return writer.ToString();
}
}
Luego devuelve el json en el método de acción de los controladores.
return Json(new
{
Html = this.RenderViewToString("MyView", model),
SomeExtraData = data
});
Sus solicitudes de ajax ahora recibirán json con el html contenido en él. Todavía estoy experimentando con este enfoque sobre la devolución de fragmentos de HTML simples.
Espero que ayude.
EDITAR Actualizado para trabajar con maquinilla de afeitar
Creo que podría devolver el html representado como una cadena. ¿Esto podría ser alternativamente una cadena html que contenga un mensaje de error para mostrar?
También puede hacerlo de esta manera, ponga esto dentro de su controlador.
protected string RenderPartialViewToString(string viewName, object model)
{
if (string.IsNullOrEmpty(viewName))
viewName = ControllerContext.RouteData.GetRequiredString("action");
ViewData.Model = model;
using (StringWriter sw = new StringWriter()) {
ViewEngineResult viewResult = ViewEngines.Engines.FindPartialView(ControllerContext, viewName);
ViewContext viewContext = new ViewContext(ControllerContext, viewResult.View, ViewData, TempData, sw);
viewResult.View.Render(viewContext, sw);
return sw.GetStringBuilder().ToString();
}
}