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.

JBeckton
fonte

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 .

Darin Dimitrov
fonte
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.

Dror
fonte
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.
    }
});
Jason
fonte
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;
    });
});
steveareeno
fonte
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>
Cheny
fonte
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.

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

user1080810
fonte
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.

Balaji Dinakaran
fonte