ASP.NET MVC ActionLink et méthode de publication


97

Quelqu'un peut-il me dire comment puis-je soumettre des valeurs à Controller en utilisant ActionLink et la méthode POST?
Je ne veux pas utiliser de boutons.
Je suppose qu'il y a quelque chose avec jquery.


1
J'ai écrit une méthode similaire à Html.ActionLink, mais elle crée un formulaire POST avec le bouton Soumettre. Je vais voir si je peux donner l'option de remplacer le bouton par le lien qui soumet le formulaire. Voir ici: stackoverflow.com/questions/3449807/…
nikib3ro

Réponses:


58

Vous ne pouvez pas utiliser un ActionLinkcar cela rend simplement une <a>balise d' ancrage .
Vous pouvez utiliser une publication jQuery AJAX .
Ou appelez simplement la méthode submit du formulaire avec ou sans jQuery (qui ne serait pas AJAX), peut-être en onclickcas de contrôle de votre choix.


70

Si vous utilisez ASP MVC3, vous pouvez utiliser un Ajax.ActionLink (), qui vous permet de spécifier une méthode HTTP que vous pouvez définir sur "POST".


45
Notez que pour que cela fonctionne, vous devrez inclure l'un des fichiers javascript ajax, par exemple " jquery.unobtrusive-ajax.min.js". Sinon, il continuera à faire un GET au lieu d'un POST lorsque vous cliquez dessus. La syntaxe pour créer le lien serait la suivante:@Ajax.ActionLink("Delete", "Delete", new { id = item.Id }, new AjaxOptions {HttpMethod = "POST"})
CodingWithSpike

1
ajax discret fonctionnait bien MAIS j'ai dû utiliser le lien d'action un peu différemment, en passant un Dictionary comme paramètre au lieu de cet objet AjaxOptions: stackoverflow.com/a/10657891/429521 De plus, j'ai dû passer les attributs ajax à la main pour que le JS pouvait capturer et remplacer les événements de clic, ils l'étaient "data-ajax"="true, "data-ajax-url"=<your link> and "data-ajax-method"="Post". Btw, j'utilise ASP.NET MVC 3
Felipe Sabino

1
@CokoBWare celui-ci stackoverflow.com/questions/10507737/... ? vraiment? Cela ne semble pas être cassé pour moi ...
Felipe Sabino

20

Vous pouvez utiliser jQuery pour faire un POST pour tous vos boutons. Donnez-leur simplement le même nom CssClass.

Utilisez "return false;" à la fin de votre événement javascript onclick si vous voulez faire un RedirectToAction côté serveur après la publication, sinon renvoyez simplement la vue.

Code du rasoir

@using (Html.BeginForm())
{
    @Html.HiddenFor(model => model.ID) 
    @Html.ActionLink("Save", "SaveAction", "MainController", null, new { @class = "saveButton", onclick = "return false;" })
}

Code JQuery

$(document).ready(function () {
        $('.saveButton').click(function () {
            $(this).closest('form')[0].submit();
        });
    });

C #

[AcceptVerbs(HttpVerbs.Post)]
public ActionResult SaveAction(SaveViewModel model)
{
    // Save code here...

    return RedirectToAction("Index");
    //return View(model);
}

@ goodies4uall En effet, et cette réponse fait exactement cela. :) La classe CSS est nommée "saveButton" (peut-être un nom trompeur), mais une balise d'ancrage est utilisée pour lancer l'action
Savantes

18

@Aidos avait la bonne réponse, je voulais juste que ce soit clair car elle est cachée dans un commentaire sur son message fait par @CodingWithSpike.

@Ajax.ActionLink("Delete", "Delete", new { id = item.ApkModelId }, new AjaxOptions { HttpMethod = "POST" })

6

Voici une réponse intégrée au projet ASP.NET MVC 5 par défaut qui, je crois, accomplit bien mes objectifs de style dans l'interface utilisateur. Soumettez le formulaire en utilisant du javascript pur à un formulaire contenant.

@using (Html.BeginForm("Logout", "Account", FormMethod.Post, new { id = "logoutForm", @class = "navbar-right" }))
{
   <a href="javascript:document.getElementById('logoutForm').submit()">
      <span>Sign out</span>
   </a>
}

Le cas d'utilisation entièrement illustré est une liste déroulante de déconnexion dans la barre de navigation d'une application Web.

@using (Html.BeginForm("Logout", "Account", FormMethod.Post, new { id = "logoutForm", @class = "navbar-right" }))
{
    @Html.AntiForgeryToken()

    <div class="dropdown">
        <button type="button" class="btn btn-default dropdown-toggle" data-toggle="dropdown">
            <span class="ma-nav-text ma-account-name">@User.Identity.Name</span>
            <i class="material-icons md-36 text-inverse">person</i>
        </button>

        <ul class="dropdown-menu dropdown-menu-right ma-dropdown-tray">
            <li>
                <a href="javascript:document.getElementById('logoutForm').submit()">
                    <i class="material-icons">system_update_alt</i>
                    <span>Sign out</span>
                </a>
            </li>
        </ul>
    </div>
}

3

ActionLink ne déclenchera jamais le message. Il déclenche toujours la requête GET.


2

Utilisez ce qui suit le lien Appel à l'action:

<%= Html.ActionLink("Click Here" , "ActionName","ContorllerName" )%>

Pour soumettre les valeurs du formulaire, utilisez:

 <% using (Html.BeginForm("CustomerSearchResults", "Customer"))
   { %>
      <input type="text" id="Name" />
      <input type="submit" class="dASButton" value="Submit" />
   <% } %>

Il soumettra les données au contrôleur du client et à l'action CustomerSearchResults.


1

Utilisez ce lien dans Ajax.BeginForm

@Html.ActionLink(
    "Save", 
    "SaveAction", 
    null, 
    null, 
    onclick = "$(this).parents('form').attr('action', $(this).attr('href'));$(this).parents('form').submit();return false;" })

;)


1

Ma solution à ce problème est assez simple. J'ai une page qui effectue une recherche client l'un par l'e-mail entier et l'autre par un partiel, le partiel tire et affiche une liste la liste a un lien d'action qui pointe vers un résultat d'action appelé GetByID et passe l'id

le GetByID extrait les données du client sélectionné puis retourne

return View("Index", model); 

quelle est la méthode post


1

Cela a été un problème difficile à résoudre pour moi. Comment puis-je créer un lien dynamique en rasoir et html qui peut appeler une méthode d'action et transmettre une valeur ou des valeurs à une méthode d'action spécifique? J'ai envisagé plusieurs options, y compris un assistant html personnalisé. Je viens de proposer une solution simple et élégante.

La vue

@model IEnumerable<MyMvcApp.Models.Product>

@using (Html.BeginForm()) {

     <table>
         <thead>
             <tr>
                 <td>Name</td>
                 <td>Price</td>
                 <td>Quantity</td>
            </tr>
        </thead>
        @foreach (Product p in Model.Products)
        {
            <tr>
                <td><a href="@Url.Action("Edit", "Product", p)">@p.Name</a></td>
                <td>@p.Price.ToString()</td>
                <td>@p.Quantity.ToString()</td>
            </tr>
         }
    </table>
}

La méthode d'action

public ViewResult Edit(Product prod)
{
    ContextDB contextDB = new ContextDB();

    Product product = contextDB.Products.Single(p => p.ProductID == prod.ProductId);

    product = prod;

    contextDB.SaveChanges();

    return View("Edit");
}

Le point ici est que Url.Action ne se soucie pas de savoir si la méthode d'action est un GET ou un POST. Il accédera à l'un ou l'autre type de méthode. Vous pouvez transmettre vos données à la méthode d'action en utilisant

@Url.Action(string actionName, string controllerName, object routeValues)

l'objet routeValues. J'ai essayé ceci et cela fonctionne. Non, vous n'êtes pas techniquement en train de publier un message ou de soumettre le formulaire, mais si l'objet routeValues ​​contient vos données, peu importe qu'il s'agisse d'un message ou d'un get. Vous pouvez utiliser une signature de méthode d'action particulière pour sélectionner la bonne méthode.


1
J'ai essayé votre échantillon et le navigateur envoie GET au serveur, même le formulaire est de type Post. Si actionMethod dans le contrôleur a l'attribut [HttpPost], la demande échoue car la route est introuvable.
Vitaliy Markitanov du

1

J'ai fait le même problème en utilisant le code suivant:

@using (Html.BeginForm("Delete", "Admin"))
{
       @Html.Hidden("ProductID", item.ProductID)
       <input type="submit" value="Delete" />
}

Si vous avez de nombreux éléments sur la page, vous devrez mettre chacun d'eux en forme, et par conséquent, de nombreux formulaires seront générés. <Input type = submit> rend également le bouton, pas le lien.
Vitaliy Markitanov

@VitaliyMarkitanov vous suggérez d'utiliser jQuery ajax?
isxaker

Regardez mon post ci-dessous dans ce fil, j'y ai expliqué ma solution.
Vitaliy Markitanov du

Dans l'exemple de projet MVC, c'est à peu près exactement ce qu'ils font aussi
Maya

1

Ceci est ma solution au problème. Ceci est un contrôleur avec 2 méthodes d'action

public class FeedbackController : Controller
{
public ActionResult Index()
{
   var feedbacks =dataFromSomeSource.getData;
   return View(feedbacks);
}

[System.Web.Mvc.HttpDelete]
[System.Web.Mvc.Authorize(Roles = "admin")]
public ActionResult Delete([FromBody]int id)
{
   return RedirectToAction("Index");
}
}

Dans View, je rends la structure suivante.

<html>
..
<script src="~/Scripts/bootbox.min.js"></script>
<script>
function confirmDelete(id) {
  bootbox.confirm('@Resources.Resource.AreYouSure', function(result) {
    if (result) {
      document.getElementById('idField').value = id;
      document.getElementById('myForm').submit();
    }
  }.bind(this));
}
</script>

@using (Html.BeginForm("Delete", "Feedback", FormMethod.Post, new { id = "myForm" }))
{
  @Html.HttpMethodOverride(HttpVerbs.Delete)
  @Html.Hidden("id",null,new{id="idField"})
  foreach (var feedback in @Model)
  {
   if (User.Identity.IsAuthenticated && User.IsInRole("admin"))
   {
    @Html.ActionLink("Delete Item", "", new { id = @feedback.Id }, new { onClick = "confirmDelete("+feedback.Id+");return false;" })
   }
  }
...
</html>

Point d'intérêt dans Razor View :

  1. Fonction JavaScript confirmDelete(id)qui est appelée lorsque le lien généré avec @Html.ActionLinkest cliqué;

  2. confirmDelete()fonction requise id de l'élément cliqué. Cet élément est passé par le onClickgestionnaire confirmDelete("+feedback.Id+");return false;. Le gestionnaire de prêter attention renvoie false pour empêcher l'action par défaut - qui consiste à obtenir la demande à la cible. OnClickL'événement pour les boutons pourrait être attaché avec jQuery pour tous les boutons de la liste comme alternative (ce sera probablement encore mieux, car il y aura moins de texte dans la page HTML et les données pourraient être transmises via l' data-attribut).

  3. Form a id=myForm, afin de le trouver dans confirmDelete().

  4. Le formulaire inclut @Html.HttpMethodOverride(HttpVerbs.Delete)pour utiliser le HttpDeleteverbe, comme action marquée avec le HttpDeleteAttribute.

  5. Dans la fonction JS, j'utilise la confirmation d'action (avec l'aide d'un plugin externe, mais la confirmation standard fonctionne bien aussi. N'oubliez pas d'utiliser bind()dans le rappel ou var that=this(ce que vous préférez).

  6. Form a un élément caché avec id='idField'et name='id'. Donc, avant que le formulaire ne soit soumis après confirmation ( result==true), la valeur de l'élément caché est définie sur valeur argument passé et le navigateur soumettra les données au contrôleur comme ceci:

URL de la demande :http://localhost:38874/Feedback/Delete

Méthode de demande : Code d'état POST: 302 trouvé

En-têtes de réponse

Emplacement: / Commentaires Host: localhost: 38874 Form Data X-HTTP-Method-Override: DELETE id: 5

Comme vous le voyez, il s'agit d'une requête POST avec X-HTTP-Method-Override: DELETE et les données du corps sont définies sur "id: 5". La réponse a un code 302 qui redirige vers l'action d'indexation, vous actualisez ainsi votre écran après la suppression.


0

Je recommanderais de rester fidèle aux principes REST et d'utiliser une suppression HTTP pour vos suppressions. Malheureusement, les spécifications HTML n'ont que HTTP Get & Post. Une balise ne peut qu'un HTTP Get. Une balise de formulaire peut effectuer une récupération HTTP ou une publication. Heureusement, si vous utilisez ajax, vous pouvez faire une suppression HTTP et c'est ce que je recommande. Voir l'article suivant pour plus de détails: Suppressions Http


0

L'appel de $ .post () ne fonctionnera pas car il est basé sur Ajax. Une méthode hybride doit donc être utilisée à cette fin.

Voici la solution qui fonctionne pour moi.

Étapes: 1. Créez une URL pour href qui appelle la méthode a avec l'URL et le paramètre 2. Appelez le POST normal en utilisant la méthode JavaScript

Solution:

Dans .cshtml:

<a href="javascript:(function(){$.postGo( '@Url.Action("View")', { 'id': @receipt.ReceiptId  } );})()">View</a>

Remarque: la méthode anonyme doit être enveloppée dans (....) () ie

(function() {
    //code...
})();

postGo est défini comme ci-dessous dans JavaScript. Le repos est simple.

@ Url.Action ("View") crée l'URL de l'appel

{'id': @ reception.ReceiptId} crée des paramètres en tant qu'objet qui est à son tour converti en champs POST dans la méthode postGo. Cela peut être n'importe quel paramètre selon vos besoins

En JavaScript:

(function ($) {
    $.extend({
        getGo: function (url, params) {
            document.location = url + '?' + $.param(params);
        },
        postGo: function (url, params) {
            var $form = $("<form>")
                .attr("method", "post")
                .attr("action", url);
            $.each(params, function (name, value) {
                $("<input type='hidden'>")
                    .attr("name", name)
                    .attr("value", value)
                    .appendTo($form);
            });
            $form.appendTo("body");
            $form.submit();
        }
    });
})(jQuery);

URL de référence que j'ai utilisées pour postGo

GET / POST non-ajax utilisant jQuery (plugin?)

http://nuonical.com/jquery-postgo-plugin/


0

jQuery.post()fonctionnera si vous avez des données personnalisées. Si vous souhaitez publier un formulaire existant, il est plus facile à utiliser ajaxSubmit().

Et vous n'avez pas besoin de configurer ce code dans le ActionLink lui même, car vous pouvez attacher un gestionnaire de lien à l' document.ready()événement (qui est de toute façon une méthode préférée), par exemple en utilisant $(function(){ ... })jQuery trick.


0

Je suis tombé sur ce besoin de POST depuis une page de recherche (index) vers la page de résultats. Je n'avais pas besoin d'autant que @Vitaliy l'a déclaré, mais cela m'a orienté dans la bonne direction. Tout ce que j'avais à faire était ceci:

@using (Html.BeginForm("Result", "Search", FormMethod.Post)) {
  <div class="row">
    <div class="col-md-4">
      <div class="field">Search Term:</div>
      <input id="k" name="k" type="text" placeholder="Search" />
    </div>
  </div>
  <br />
  <div class="row">
    <div class="col-md-12">
      <button type="submit" class="btn btn-default">Search</button>
    </div>
  </div>
}

Mon contrôleur avait la méthode de signature suivante:

[HttpPost]
public async Task<ActionResult> Result(string k)

0

Ceci est tiré de l'exemple de projet MVC

@if (ViewBag.ShowRemoveButton)
      {
         using (Html.BeginForm("RemoveLogin", "Manage"))
           {
              @Html.AntiForgeryToken()
                  <div>
                     @Html.Hidden("company_name", account)
                     @Html.Hidden("returnUrl", Model.returnUrl)
                     <input type="submit" class="btn btn-default" value="Remove" title="Remove your email address from @account" />
                  </div>
            }
        }
En utilisant notre site, vous reconnaissez avoir lu et compris notre politique liée aux cookies et notre politique de confidentialité.
Licensed under cc by-sa 3.0 with attribution required.