Utilisation d'Ajax.BeginForm avec ASP.NET MVC 3 Razor

264

Existe-t-il un didacticiel ou un exemple de code d'utilisation Ajax.BeginFormdans Asp.net MVC 3 où la validation discrète et Ajax existent?

C'est un sujet insaisissable pour MVC 3, et je n'arrive pas à faire fonctionner correctement mon formulaire. Il fera une soumission Ajax mais ignorera les erreurs de validation.

JBeckton
la source

Réponses:

427

Exemple:

Modèle:

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

Manette:

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

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

Vue:

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

et voici un meilleur exemple (à mon avis):

Vue:

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

qui peut être encore amélioré avec le plugin de formulaire jQuery .

Darin Dimitrov
la source
41
Je suis d'accord sur l'utilisation de jQUery pour Ajax. Je pense que la grande majorité des applications Asp.net MVC Ajax utilisent plutôt jQuery que les extensions Ajax intégrées.
Robert Koritnik
6
J'utilise quelque chose comme ce qui suit et le résultat semble aller sur sa propre page et non pas simplement remplacer un résultat div. Est-ce que tu sais pourquoi?
David
3
Oui, je suis également d'accord sur l'utilisation de jQuery pur pour ajax, l'utilisation de l'extension ajax MVC signifie que vous devez apprendre d'autres règles et syntaxe inutiles pour, à la fin, utiliser jQuery. Donc, même moi, j'ai besoin d'écrire plus, mais il vaut mieux le faire dans le bon sens, en plus vous obtenez plus de contrôle et de flexibilité.
Nestor
3
@ darin-dimitrov: lorsque j'essaie votre dernier exemple, je dois ajouter des données: $ ('form'). serialize (), à l'appel ajax (). Sinon, aucune donnée de formulaire n'est transmise et mon modèle n'est pas valide côté serveur. Vous vous demandez s'il y a quelque chose que j'ai oublié?
Brett
2
@DarinDimitrov que faire s'il y a une erreur avec le BLL et que vous devez renvoyer le modèle à la vue et afficher le message d'erreur parce que la couche renforcée a fourni une validation plus approfondie des données et a trouvé un problème. Il ne suffit pas de se fier uniquement à la validation côté client. Vous ne pouvez pas retourner View (modèle); maintenant parce que la vue entière est rendue dans le résultat div ... quelle est la solution pour cela?
CD Smith
54

Je pense que toutes les réponses ont manqué un point crucial:

Si vous utilisez le formulaire Ajax pour qu'il doive se mettre à jour lui-même (et NON un autre div en dehors du formulaire), vous devez placer le div contenant à l' extérieur du formulaire. Par exemple:

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

Sinon, vous finirez comme @David où le résultat est affiché dans une nouvelle page.

Dror
la source
7
Le problème de David est presque toujours causé par le fait de ne pas inclure le paquet jqueryval qui contient le code ajax discret. Soyez très prudent avec cette approche que vous avez publiée, sinon vous obtiendrez un poste et votre formulaire sera arrosé puisque vous venez de le remplacer. Vous avez ensuite besoin de la vue de "MyAction" pour gérer son formulaire et re-spécifier toutes les options ajax qu'il contient.
Adam Tuliper - MSFT
Dans mon application ciblée div montrant le formulaire entier avec la page principale, aidez-moi
Nitin ...
Pour moi, je ne m'étais mis UnobtrusiveJavaScriptEnabledà vrai nulle part
Kunal
15

J'ai finalement réussi à faire fonctionner la solution de Darin, mais j'ai d'abord fait quelques erreurs, ce qui a entraîné un problème similaire à David (dans les commentaires ci-dessous, la solution de Darin), où le résultat était publié sur une nouvelle page.

Parce que je devais faire quelque chose avec le formulaire après le retour de la méthode, je l'ai stocké pour une utilisation ultérieure:

var form = $(this);

Cependant, cette variable n'avait pas les propriétés "action" ou "méthode" qui sont utilisées dans l'appel 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();
});

Au lieu de cela, vous devez utiliser la variable "this":

$.ajax({
    url: this.action, 
    type: this.method,
    data: $(this).serialize(),
    success: function (html) {
        // Do something with the returned html.
    }
});
Jason
la source
5
C'est parce que la variable de formulaire que vous lui avez défini l' jQueryobjet avec formulaire comme sélecteur. form[0]aurait les propriétés. Il est également recommandé de préfixer toutes les jQueryvariables $pour les identifier plus facilement.
James South
6

La solution de Darin Dimitrov a fonctionné pour moi à une exception près. Lorsque j'ai soumis la vue partielle avec des erreurs de validation (intentionnelles), j'ai fini par retourner des formulaires en double dans la boîte de dialogue:

entrez la description de l'image ici

Pour résoudre ce problème, j'ai dû envelopper le Html.BeginForm dans une div:

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

Lorsque le formulaire a été soumis, j'ai effacé le div dans la fonction de réussite et sorti le formulaire validé:

    $('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
la source
Moi aussi, je reçois la même erreur. J'utilise Partial Viewspour rendre la fonction de création sous la page d'index. Je peux obtenir tous les messages de validation dans la vue partielle. Mais lorsque le Createréussit, l'index s'affiche deux fois. Je n'ai aucun Html.BeginFormdans ma vue d'index.
Vini
Essayez d'utiliser à la UpdateTargetId = "myForm"place
Kunal
4

Si aucune validation de données n'est exécutée ou si le contenu est toujours renvoyé dans une nouvelle fenêtre, assurez-vous que ces 3 lignes sont en haut de la vue:

<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
la source
Je ne les ai pas trouvés en solution. J'ai dû les installer à partir du gestionnaire de paquets
Nuget
3

Exemple

// Dans le modèle

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

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

Dans la vue 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>
}

Dans le contrôleur

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

vous devez passer ViewName et Model à la méthode RenderPartialViewToString. il vous renverra la vue avec validation à laquelle vous êtes appliqué dans le modèle et ajoutera le contenu dans "targetId" div dans Index.cshtml. De cette façon, en attrapant RenderHtml de vue partielle, vous pouvez appliquer la validation.

Shivkumar
la source
3

Les formulaires Ajax fonctionnent de manière asynchrone en utilisant Javascript. Il est donc nécessaire de charger les fichiers de script pour exécution. Même s'il s'agit d'un petit compromis sur les performances, l'exécution se produit sans publication.

Nous devons comprendre la différence entre les comportements des formulaires Html et Ajax.

Ajax:

  1. Ne redirige pas le formulaire, même si vous effectuez une RedirectAction ().

  2. Effectue la sauvegarde, la mise à jour et toute opération de modification de manière asynchrone.

Html:

  1. Redirigera le formulaire.

  2. Effectue des opérations à la fois de manière synchrone et asynchrone (avec un peu de code et d'attention supplémentaires).

Démontré les différences avec un POC dans le lien ci-dessous. Lien

user1080810
la source
1

Avant d'ajouter Ajax.BeginForm. Ajoutez les scripts ci-dessous à votre projet dans l'ordre indiqué,

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

Seuls ces deux sont suffisants pour effectuer une opération Ajax.

Balaji Dinakaran
la source