Vista parcial de representación de ASP.NET MVC con jQuery ajax

Tengo una acción de controlador que muestra una vista parcial:

public ActionResult Details(int id) { DetailsViewModel model = ModelBuilder.GetDetailsViewModel(id, _repository); return PartialView("Details", model); } 

y estoy cargando el contenido devuelto en un elemento dynamic de la siguiente manera:

 $container = appendContainer(); // adds a div to the dom with the correct id $container.load("MyController/Details", function(response, status, xhr) { if (status != "success") { $(container).html('an error has occured'); } }); 

entonces esto crea un div, y luego carga el contenido devuelto en ese div.

Quiero modificar esto ligeramente para que el contenedor div solo se cree si la llamada al controlador es exitosa.

Asi que:

  1. jQuery llama a la acción del controlador
  2. El controlador devuelve PartialView o null si no se encuentra Id.
  3. Si se devuelve PartialView, el contenedor se crea y se carga con el contenido devuelto.
  4. Si el controlador no encuentra el Id, no se crea contenido y se muestra una alerta.

Agradecería cualquier sugerencia sobre cómo podría lograr esto.

Todo lo que load es devolver HTML desde un servidor, entonces ¿por qué no solo anexar a un div temporal y luego obtener el HTML del mismo en caso de éxito?

 var $dummy = $("
"); $dummy.load("MyController/Details", function(response, status, xhr) { var $container = appendContainer(); if (status != "success") { $container.html('an error has occured'); } else { $container.html($dummy.html()); } $dummy.remove(); });

ACTUALIZAR:

Si esperas una excepción, entonces debes manejarla. ¡Si básicamente permites que se produzca el error solo para obtener el status != "success" entonces ese es un olor a código serio. Debería detectar el error y devolver un PartialView diferente.

 public ActionResult Details(int id) { try { DetailsViewModel model = ModelBuilder.GetDetailsViewModel(id, _repository); return PartialView("Details", model); } catch (SomeException ex) { return PartialView("Error", ex.Message); } } 

Entonces, se garantiza que siempre obtendrás una respuesta HTML válida y, si no lo haces, se activará tu error básico.

en su caso, usaría $ .ajax en lugar de .load () le da más control sobre el flujo + se siente más limpio

 $.ajax({ url: "MyController/Details", type: "GET", success: function (response, status, xhr) { var jqContainer = appendContainer(); jqContainer.html(response); }, error:function(XMLHttpRequest, textStatus, errorThrown) { //show the error somewhere - but this is a bad solution } }); 

sobre el estado de error – también odio confiar en las excepciones – feo e ineficiente, usted tiene varias formas de manejar esto:

  1. devuelva solo JSON de sus vistas y vincule los datos devueltos utilizando algún tipo de solución de plantillas, de esta forma puede devolver un objeto de error con un mensaje de error específico y manejar todos los errores de la misma manera (piense que esta es la mejor solución).
  2. devuelve un código de estado de éxito de 204 -ninguna respuesta que es como devolver el valor nulo de tu acción- luego verifica el código de estado y aparece el mensaje de error.
  3. devuelve un código de estado de éxito 278 (no es un código de estado real, pero cuenta para tener éxito y también le permite enviar datos); aquí envía un objeto json con el mensaje de error que tou puede analizar y sembrar un mensaje de error agradable (vio esta solución 278 aquí en SO hace algún tiempo).
  4. devuelva una vista diferente del error, pero luego debe insertarlo en el contenedor o en un contenedor ficticio para verificar si hay un error si desea realizar más acciones.

en mi código, uso $ (document) .ajaxSend (..) para verificar globalmente todas las respuestas de Ajax para el código 278 y mostrar los mensajes de error si los hay, o llamar a la función de éxito enganchada original.

Para devolver el error de la acción, uso el siguiente resultado

  public class AjaxErrorWithDetailsResult : JsonResult { public object ErrorResult { get; set; } public AjaxErrorWithDetailsResult(object errorResult) { this.ErrorResult = errorResult; } public override void ExecuteResult(ControllerContext context) { if (context == null) { throw new ArgumentNullException("context"); } this.Data = ErrorResult; context.HttpContext.Response.StatusCode = 278; base.ExecuteResult(context); } } 

donde ErrorResult puede ser un objeto anónimo o un objeto que implementa una interfaz con una propiedad de ErrorMessage para que sepa qué buscar en el JS