Usando o Ajax.BeginForm com o ASP.NET MVC 3 Razor


264

Existe um tutorial ou exemplo de código de uso Ajax.BeginFormno Asp.net MVC 3 onde existe validação discreta e Ajax?

Este é um tópico indescritível para o MVC 3, e parece que não consigo fazer com que meu formulário funcione corretamente. Ele fará um envio do Ajax, mas ignora os erros de validação.

Respostas:


427

Exemplo:

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

Visão:

@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" />
}

e aqui está um exemplo melhor (na minha perspectiva):

Visão:

@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 pode ser aprimorado ainda mais com o plug-in de formulário jQuery .


41
Concordo em usar o jQUery para Ajax. Eu acho que a grande maioria dos aplicativos Asp.net MVC Ajax prefere usar o jQuery do que as extensões internas do Ajax.
— Robert Koritnik 24/03

6
Estou usando algo como o seguinte e o resultado parece estar indo para sua própria página e não apenas substituindo um resultado div. Você sabe por quê?
— David

3
Sim, também concordo em usar o jQuery puro para ajax. Usar a extensão MVC ajax significa que você precisa aprender outras regras e sintaxe desnecessárias para, no final, usar o jQuery. Então, mesmo eu preciso escrever mais, mas é melhor fazê-lo da maneira certa, além de obter mais controle e flexibilidade.
— Nestor

3
@ darin-dimitrov: quando tento seu último exemplo, devo adicionar dados: $ ('form'). serialize () à chamada ajax (). Caso contrário, nenhum dado de formulário será passado e meu modelo será inválido no servidor. Gostaria de saber se há algo que eu negligenciei?
— Brett

2
@DarinDimitrov, e se houver um erro no BLL e você precisar enviar o modelo de volta para o View e mostrar a mensagem de erro porque a camada reforçada forneceu uma validação mais profunda dos dados e encontrou um problema. Apenas confiar na validação do lado do cliente não é suficiente. Você não pode retornar View (modelo); agora porque toda a exibição é renderizada na div resultado ... qual é a solução alternativa para isso?
— CD Smith

54

Eu acho que todas as respostas perderam um ponto crucial:

Se você usar o formulário Ajax para que ele precise se atualizar (e NÃO outra div fora do formulário), será necessário colocar a div contida FORA do formulário. Por exemplo:

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

Caso contrário, você terminará como @David, onde o resultado será exibido em uma nova página.


7
O problema de David é quase sempre causado por não incluir o pacote jqueryval que contém o código ajax discreto. Tenha muito cuidado com essa abordagem que você publicou, caso contrário, você receberá uma postagem e seu formulário será enviado desde que você a substituiu. Você então exige que a visualização do "MyAction" gerencie seu formulário e especifique novamente todas as opções de ajax nele.
— Adam Tuliper - MSFT

Na minha aplicação alvo div forma inteira mostrando com página mestra ajuda por favor me
— Nitin ...

Para mim, eu não tinha definido UnobtrusiveJavaScriptEnabledcomo verdadeiro em qualquer lugar
— Kunal

15

Acabei conseguindo a solução de Darin, mas cometi alguns erros primeiro, o que resultou em um problema semelhante ao de David (nos comentários abaixo da solução de Darin), onde o resultado estava sendo publicado em uma nova página.

Como tive que fazer algo com o formulário após o retorno do método, guardei-o para uso posterior:

var form = $(this);

No entanto, essa variável não possui as propriedades "action" ou "method" usadas na chamada 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();
});

Em vez disso, você precisa usar a variável "this":

$.ajax({
    url: this.action, 
    type: this.method,
    data: $(this).serialize(),
    success: function (html) {
        // Do something with the returned html.
    }
});

5
Isso ocorre porque a variável de formulário que você definiu como jQueryobjeto como forma de seleção. form[0]teria as propriedades. Também é uma boa prática prefixar todas as jQueryvariáveis $para identificá-las mais facilmente.
— James South

6

A solução de Darin Dimitrov funcionou para mim com uma exceção. Quando enviei a exibição parcial com erros de validação (intencionais), acabei retornando formulários duplicados na caixa de diálogo:

insira a descrição da imagem aqui

Para corrigir isso, tive que quebrar o Html.BeginForm em uma div:

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

Quando o formulário foi enviado, limpei a div na função success e produzi o formulário 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;
    });
});

Eu também recebo o mesmo erro. Estou usando Partial Viewspara renderizar a função de criação abaixo da página de índice. Eu posso receber todas as mensagens de validação na exibição parcial. Mas quando o processo Createfor bem sucedido, o índice será exibido duas vezes. Não tenho Html.BeginFormna minha Visualização de índice.
— Vini

Tente usar em UpdateTargetId = "myForm"vez disso
— Kunal

4

Se nenhuma validação de dados tiver sido excluída ou o conteúdo sempre for retornado em uma nova janela, verifique se essas 3 linhas estão no topo da visualização:

<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>

Não os encontrei em solução. Eu tive que instalá-los a partir do gerenciador de pacotes Nuget
— FindOut_Quran

3

Exemplo

// No modelo

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

// No 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>

Na exibição 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>
}

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

você deve passar ViewName e Model para o método RenderPartialViewToString. ele retornará a visualização com validação aplicada no modelo e anexará o conteúdo na div "targetId" no Index.cshtml. Dessa maneira, capturando RenderHtml de vista parcial, você pode aplicar a validação.


3

Os formulários Ajax funcionam de forma assíncrona usando Javascript. Portanto, é necessário carregar os arquivos de script para execução. Mesmo que seja um pequeno comprometimento de desempenho, a execução ocorre sem postback.

Precisamos entender a diferença entre os comportamentos das formas Html e Ajax.

Ajax:

  1. Não redirecionará o formulário, mesmo que você faça um RedirectAction ().

  2. Realizará operações de salvamento, atualização e qualquer modificação de forma assíncrona.

Html:

  1. Irá redirecionar o formulário.

  2. Realizará operações de forma síncrona e assíncrona (com algum código e cuidado extra).

Demonstrou as diferenças com um POC no link abaixo. Ligação


1

Antes de adicionar o Ajax.BeginForm. Adicione os scripts abaixo ao seu projeto na ordem mencionada,

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

Somente esses dois são suficientes para executar a operação do Ajax.

Ao utilizar nosso site, você reconhece que leu e compreendeu nossa Política de Cookies e nossa Política de Privacidade.
Licensed under cc by-sa 3.0 with attribution required.