Usando Ajax.BeginForm con ASP.NET MVC 3 Razor

264

¿Hay un tutorial o ejemplo de código de uso Ajax.BeginFormdentro de Asp.net MVC 3 donde existe una validación discreta y Ajax?

Este es un tema evasivo para MVC 3, y parece que no puedo hacer que mi formulario funcione correctamente. Hará un envío Ajax pero ignora los errores de validación.

JBeckton
fuente

Respuestas:

427

Ejemplo:

Modelo:

public class MyViewModel
{
    [Required]
    public string Foo { get; set; }
}

Controlador:

public class HomeController : Controller
{
    public ActionResult Index()
    {
        return View(new MyViewModel());
    }

    [HttpPost]
    public ActionResult Index(MyViewModel model)
    {
        return Content("Thanks", "text/html");
    }
}

Ver:

@model AppName.Models.MyViewModel

<script src="@Url.Content("~/Scripts/jquery.unobtrusive-ajax.js")" type="text/javascript"></script>
<script src="@Url.Content("~/Scripts/jquery.validate.js")" type="text/javascript"></script>
<script src="@Url.Content("~/Scripts/jquery.validate.unobtrusive.js")" type="text/javascript"></script>

<div id="result"></div>

@using (Ajax.BeginForm(new AjaxOptions { UpdateTargetId = "result" }))
{
    @Html.EditorFor(x => x.Foo)
    @Html.ValidationMessageFor(x => x.Foo)
    <input type="submit" value="OK" />
}

y aquí hay un mejor ejemplo (en mi perspectiva):

Ver:

@model AppName.Models.MyViewModel

<script src="@Url.Content("~/Scripts/jquery.validate.js")" type="text/javascript"></script>
<script src="@Url.Content("~/Scripts/jquery.validate.unobtrusive.js")" type="text/javascript"></script>
<script src="@Url.Content("~/Scripts/index.js")" type="text/javascript"></script>

<div id="result"></div>

@using (Html.BeginForm())
{
    @Html.EditorFor(x => x.Foo)
    @Html.ValidationMessageFor(x => x.Foo)
    <input type="submit" value="OK" />
}

index.js:

$(function () {
    $('form').submit(function () {
        if ($(this).valid()) {
            $.ajax({
                url: this.action,
                type: this.method,
                data: $(this).serialize(),
                success: function (result) {
                    $('#result').html(result);
                }
            });
        }
        return false;
    });
});

que se puede mejorar aún más con el complemento de formulario jQuery .

Darin Dimitrov
fuente
41
Estoy de acuerdo en usar jQUery para Ajax. Creo que la gran mayoría de las aplicaciones Asp.net MVC Ajax prefieren jQuery que las extensiones integradas de Ajax.
Robert Koritnik
66
Estoy usando algo como lo siguiente y el resultado parece ir a su propia página y no solo reemplazar un resultado div. ¿Sabes por qué?
David
3
Sí, también estoy de acuerdo en usar jQuery puro para ajax, usar la extensión MVC ajax significa que necesitas aprender innecesariamente otras reglas y sintaxis para, al final, usar jQuery. Entonces, incluso necesito escribir más, pero es mejor hacerlo de la manera correcta, además de obtener más control y flexibilidad.
Nestor
3
@ darin-dimitrov: cuando pruebo su último ejemplo, debo agregar datos: $ ('formulario'). serialize (), a la llamada ajax (). De lo contrario, no se pasan datos del formulario y mi modelo no es válido en el lado del servidor. ¿Me pregunto si hay algo que he pasado por alto?
Brett
2
@DarinDimitrov, ¿qué pasa si hay un error con el BLL y necesita enviar el modelo de nuevo a la Vista y mostrar el mensaje de error porque la capa endurecida proporcionó una validación más profunda de los datos y encontró un problema? Solo confiar en la validación del lado del Cliente no es suficiente. No puede devolver Vista (modelo); ahora porque toda la vista se representa en el resultado div ... ¿cuál es la solución para eso?
CD Smith
54

Creo que todas las respuestas perdieron un punto crucial:

Si se utiliza el formulario Ajax por lo que tiene que actualizarse (y no otro div exterior de la forma), entonces usted necesita para poner el div que contiene FUERA de la forma. Por ejemplo:

 <div id="target">
 @using (Ajax.BeginForm("MyAction", "MyController",
            new AjaxOptions
            {
                HttpMethod = "POST",
                InsertionMode = InsertionMode.Replace,
                UpdateTargetId = "target"
            }))
 {
      <!-- whatever -->
 }
 </div>

De lo contrario, terminará como @David donde el resultado se muestra en una nueva página.

Dror
fuente
77
El problema de David casi siempre es causado por no incluir el paquete jqueryval que contiene el discreto código ajax. Ten mucho cuidado con este enfoque que publicaste; de ​​lo contrario, recibirás una publicación y luego tu formulario se actualizará, ya que lo acabas de reemplazar. Luego necesita la vista de "MyAction" para administrar su formulario y volver a especificar todas las opciones de ajax en él.
Adam Tuliper - MSFT
En mi aplicación, div que muestra el formulario completo con la página maestra, por favor, ayúdame
Nitin ...
Para mí no me había puesto UnobtrusiveJavaScriptEnableda la verdad en ninguna parte
Kunal
15

Finalmente conseguí que la solución de Darin funcionara, pero primero cometí algunos errores que resultaron en un problema similar a David (en los comentarios debajo de la solución de Darin) donde el resultado se publicaba en una nueva página.

Debido a que tuve que hacer algo con el formulario después de que el método regresó, lo almacené para su uso posterior:

var form = $(this);

Sin embargo, esta variable no tenía las propiedades "acción" o "método" que se utilizan en la llamada ajax.

$(document).on("submit", "form", function (event) {
    var form = $(this);

    if (form.valid()) {
        $.ajax({
            url: form.action, // Not available to 'form' variable
            type: form.method,  // Not available to 'form' variable
            data: form.serialize(),
            success: function (html) {
                // Do something with the returned html.
            }
        });
    }

    event.preventDefault();
});

En su lugar, debe usar la variable "this":

$.ajax({
    url: this.action, 
    type: this.method,
    data: $(this).serialize(),
    success: function (html) {
        // Do something with the returned html.
    }
});
Jason
fuente
55
Esto se debe a que la variable de formulario lo ha establecido como el jQueryobjeto con el formulario como selector. form[0]tendrían las propiedades. También es una buena práctica prefijar cualquier jQueryvariable $para identificarla más fácilmente.
James South
6

La solución de Darin Dimitrov funcionó para mí con una excepción. Cuando envié la vista parcial con errores de validación (intencionales), terminé devolviendo formularios duplicados en el cuadro de diálogo:

ingrese la descripción de la imagen aquí

Para solucionar esto, tuve que envolver el Html.BeginForm en un div:

<div id="myForm">
    @using (Html.BeginForm("CreateDialog", "SupportClass1", FormMethod.Post, new { @class = "form-horizontal" }))
    {
        //form contents
    }
</div>

Cuando se envió el formulario, borré el div en la función de éxito y envié el formulario validado:

    $('form').submit(function () {
        if ($(this).valid()) {
            $.ajax({
                url: this.action,
                type: this.method,
                data: $(this).serialize(),
                success: function (result) {
                    $('#myForm').html('');
                    $('#result').html(result);
                }
            });
        }
        return false;
    });
});
steveareeno
fuente
Yo también obtengo el mismo error. Estoy usando Partial Viewspara representar la función de creación debajo de la página de índice. Puedo obtener todos los mensajes de validación en la Vista parcial. Pero cuando Createes exitoso, el índice se muestra dos veces. No tengo Html.BeginFormen mi Vista de índice.
Vini
Intente usar en su UpdateTargetId = "myForm"lugar
Kunal
4

Si no se realizó ninguna validación de datos, o el contenido siempre se devuelve en una nueva ventana, asegúrese de que estas 3 líneas estén en la parte superior de la vista:

<script src="@Url.Content("~/Scripts/jquery.validate.min.js")" type="text/javascript"></script>
<script src="@Url.Content("~/Scripts/jquery.validate.unobtrusive.min.js")" type="text/javascript"></script>
<script src="@Url.Content("~/Scripts/jquery.unobtrusive-ajax.min.js")" type="text/javascript"></script>
cheny
fuente
No los encontré en solución. Tuve que instalarlos desde el administrador de paquetes
Nuget
3

Ejemplo

// En modelo

public class MyModel
{  
   [Required]
    public string Name{ get; set; }
}

// En PartailView //PartailView.cshtml

@model MyModel

<div>
    <div>
      @Html.LabelFor(model=>model.Name)
    </div>
    <div>
        @Html.EditorFor(model=>model.Name)
        @Html.ValidationMessageFor(model => model.Name)
    </div>
</div>

En la vista Index.cshtml

@model MyModel
<div id="targetId">
    @{Html.RenderPartial("PartialView",Model)}
</div>

@using(Ajax.BeginForm("AddName", new AjaxOptions { UpdateTargetId = "targetId", HttpMethod = "Post" }))
{
     <div>
        <input type="submit" value="Add Unit" />
    </div>
}

En el controlador

public ActionResult Index()
{
  return View(new MyModel());
}


public string AddName(MyModel model)
{
   string HtmlString = RenderPartialViewToString("PartailView",model);
   return HtmlString;
}


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();
            }
        }

debe pasar ViewName y Model al método RenderPartialViewToString. le devolverá la vista con la validación que está aplicando en el modelo y agregará el contenido en "targetId" div en Index.cshtml. De esta manera, al capturar RenderHtml de vista parcial, puede aplicar la validación.

Shivkumar
fuente
3

Los formularios Ajax funcionan de forma asíncrona usando Javascript. Por lo tanto, es obligatorio cargar los archivos de script para su ejecución. Aunque es un pequeño compromiso de rendimiento, la ejecución se realiza sin devolución de datos.

Necesitamos entender la diferencia entre los comportamientos de los formularios Html y Ajax.

Ajax:

  1. No redirigirá el formulario, incluso si realiza una Acción de redireccionamiento ().

  2. Realizará operaciones de guardado, actualización y modificación de forma asincrónica.

HTML:

  1. Redirigirá el formulario.

  2. Realizará operaciones tanto sincrónicamente como asincrónicamente (con un código adicional y cuidado).

Demostró las diferencias con un POC en el siguiente enlace. Enlace

usuario1080810
fuente
1

Antes de agregar el Ajax.BeginForm. Agregue los siguientes scripts a su proyecto en el orden mencionado,

  1. jquery-1.7.1.min.js
  2. jquery.unobtrusive-ajax.min.js

Solo estos dos son suficientes para realizar la operación Ajax.

Balaji Dinakaran
fuente