Utilizzo di Ajax.BeginForm con ASP.NET MVC 3 Razor


264

Esiste un tutorial o un esempio di codice sull'uso Ajax.BeginFormdi Asp.net MVC 3 in cui esistono validazione discreta e Ajax?

Questo è un argomento sfuggente per MVC 3 e non riesco a far funzionare correttamente il mio modulo. Farà un invio Ajax ma ignora gli errori di validazione.

Risposte:


427

Esempio:

Modello:

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

controller:

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

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

Visualizza:

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

ed ecco un esempio migliore (nella mia prospettiva):

Visualizza:

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

che può essere ulteriormente migliorato con il plugin del modulo jQuery .


41
Sono d'accordo sull'uso di jQUery per Ajax. Penso che la stragrande maggioranza delle applicazioni Asp.net MVC Ajax preferisca usare jQuery piuttosto che le estensioni Ajax integrate.
Robert Koritnik,

6
Sto usando qualcosa di simile al seguente e il risultato sembra andare sulla propria pagina e non solo sostituire un risultato div. Sai perché?
David,

3
Sì, sono d'accordo anche sull'uso di jQuery puro per Ajax, l'uso dell'estensione MVC Ajax significa che è necessario apprendere altre regole e sintassi non necessarie per utilizzare jQuery. Quindi anche io ho bisogno di scrivere di più, ma è meglio farlo nel modo giusto, inoltre avrai più controllo e flessibilità.
Nestor,

3
@ darin-dimitrov: quando provo il tuo ultimo esempio, devo aggiungere dati: $ ('form'). serialize (), alla chiamata ajax (). Altrimenti, non vengono passati dati del modulo e il mio modello non è valido sul lato server. Mi chiedo se c'è qualcosa che ho trascurato?
Brett,

2
@DarinDimitrov cosa succede se si verifica un errore con BLL ed è necessario inviare nuovamente il modello alla vista e mostrare il messaggio di errore perché il livello rinforzato ha fornito una convalida più profonda sui dati e ha riscontrato un problema. Basarsi sulla convalida lato client non è sufficiente. Non è possibile restituire Visualizza (modello); ora perché l'intera vista viene renderizzata nel risultato div ... qual è la soluzione per questo?
CD Smith,

54

Penso che tutte le risposte abbiano perso un punto cruciale:

Se si utilizza il modulo Ajax in modo che debba aggiornarsi (e NON un altro div al di fuori del modulo), è necessario inserire il div contenente ESTERNO del modulo. Per esempio:

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

Altrimenti finirai come @David dove il risultato viene visualizzato in una nuova pagina.


7
Il problema di David è quasi sempre causato dal fatto di non includere il bundle jqueryval che contiene il codice ajax discreto. Fai molta attenzione con questo approccio che hai pubblicato, altrimenti riceverai un post e il tuo modulo verrà nascosto poiché lo hai appena sostituito. È quindi necessario il punto di vista di "MyAction" per gestirne il modulo e specificare nuovamente tutte le opzioni ajax in esso contenute.
Adam Tuliper - MSFT,

Nella mia applicazione div mirato che mostra l'intero modulo con la pagina principale per favore aiutatemi
Nitin ...

Per me non avevo impostato il UnobtrusiveJavaScriptEnabledvero da nessuna parte
Kunal il

15

Alla fine ho fatto funzionare la soluzione di Darin, ma prima ho fatto alcuni errori che hanno provocato un problema simile a David (nei commenti sotto la soluzione di Darin) in cui il risultato è stato pubblicato su una nuova pagina.

Poiché ho dovuto fare qualcosa con il modulo dopo la restituzione del metodo, l'ho archiviato per un uso successivo:

var form = $(this);

Tuttavia, questa variabile non aveva le proprietà "action" o "method" utilizzate nella chiamata 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();
});

Invece è necessario utilizzare la variabile "this":

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

5
Questo perché la variabile form lo hai impostato come jQueryoggetto con selettore come form. form[0]avrebbe le proprietà. È anche buona norma aggiungere un prefisso a qualsiasi jQueryvariabile $per identificarle più facilmente.
James South,

6

La soluzione di Darin Dimitrov ha funzionato per me con un'eccezione. Quando ho inviato la vista parziale con errori di convalida (intenzionali), ho finito con la restituzione di moduli duplicati nella finestra di dialogo:

inserisci qui la descrizione dell'immagine

Per risolvere questo problema ho dovuto avvolgere Html.BeginForm in un div:

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

Quando il modulo è stato inviato, ho cancellato il div nella funzione di successo e prodotto il modulo convalidato:

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

Anch'io ricevo lo stesso errore. Sto usando Partial Viewsper rendere la funzione di creazione sotto la pagina dell'indice. Posso ottenere tutti i messaggi di convalida nella vista parziale. Ma quando l'operazione ha Createesito positivo l'indice viene visualizzato due volte. Non ho Html.BeginFormnella mia vista indice.
Vini,

Prova ad usare UpdateTargetId = "myForm"invece
Kunal

4

Se non viene eseguita alcuna convalida dei dati o il contenuto viene sempre restituito in una nuova finestra, assicurarsi che queste 3 righe siano nella parte superiore della 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>

Non li ho trovati in soluzione. Ho dovuto installarli dal gestore dei pacchetti Nuget
FindOut_Quran

3

Esempio

// Nel modello

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

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

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

Nel controller

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

devi passare ViewName e Model al metodo RenderPartialViewToString. restituirà la visualizzazione con convalida quali sono stati applicati nel modello e aggiungere il contenuto nel div "targetId" in Index.cshtml. In questo modo catturando RenderHtml di vista parziale è possibile applicare la convalida.


3

I moduli Ajax funzionano in modo asincrono utilizzando Javascript. Quindi è necessario caricare i file di script per l'esecuzione. Anche se è un piccolo compromesso delle prestazioni, l'esecuzione avviene senza postback.

Dobbiamo capire la differenza tra i comportamenti di entrambe le forme Html e Ajax.

Ajax:

  1. Non reindirizzerà il modulo, anche tu fai un RedirectAction ().

  2. Eseguirà operazioni di salvataggio, aggiornamento e qualsiasi modifica in modo asincrono.

html:

  1. Reindirizzerà il modulo.

  2. Eseguirà operazioni sia in modo sincrono che asincrono (con un po 'di codice e attenzione in più).

Dimostrato le differenze con un POC nel link sottostante. collegamento


1

Prima di aggiungere Ajax.BeginForm. Aggiungi gli script di seguito al tuo progetto nell'ordine indicato,

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

Solo questi due sono sufficienti per eseguire l'operazione Ajax.

Utilizzando il nostro sito, riconosci di aver letto e compreso le nostre Informativa sui cookie e Informativa sulla privacy.
Licensed under cc by-sa 3.0 with attribution required.