ASP.NET MVC ActionLink i metoda post

97

Czy ktoś może mi powiedzieć, jak mogę przesłać wartości do kontrolera za pomocą metody ActionLink i POST?
Nie chcę używać przycisków.
Myślę, że ma coś z jQuery.

šljaker
źródło
1
Napisałem metodę podobną do Html.ActionLink, tyle że buduje formularz POST z przyciskiem Prześlij. Zobaczę, czy mogę dać opcję zastąpienia przycisku linkiem, który przesyła formularz. Zobacz tutaj: stackoverflow.com/questions/3449807/ ...
nikib3ro

Odpowiedzi:

58

Nie możesz użyć, ActionLinkponieważ po prostu renderuje <a>tag kotwicy .
Możesz użyć posta jQuery AJAX .
Lub po prostu wywołaj metodę przesyłania formularza z lub bez jQuery (który byłby inny niż AJAX), być może w onclickprzypadku dowolnej kontroli.

AUSteve
źródło
70

Jeśli używasz ASP MVC3, możesz użyć Ajax.ActionLink (), która pozwala określić metodę HTTP, którą możesz ustawić na „POST”.

Aidos
źródło
45
Zauważ, że aby to zadziałało, będziesz musiał dołączyć jeden z plików JavaScript javascript, na przykład „ jquery.unobtrusive-ajax.min.js”. W przeciwnym razie po kliknięciu będzie nadal wykonywał GET zamiast POST. Składnia do utworzenia linku byłaby następująca:@Ajax.ActionLink("Delete", "Delete", new { id = item.Id }, new AjaxOptions {HttpMethod = "POST"})
CodingWithSpike,
1
dyskretny ajax działał dobrze, ALE musiałem użyć łącza do akcji nieco inaczej, przekazując parametr Dictionary jako parametr zamiast tego obiektu AjaxOptions: stackoverflow.com/a/10657891/429521 Ponadto musiałem ręcznie przekazać atrybuty ajax, aby JS mógł przechwytywać i zastępować zdarzenia związane z kliknięciami "data-ajax"="true, "data-ajax-url"=<your link> and "data-ajax-method"="Post". Przy okazji, używam ASP.NET MVC 3
Felipe Sabino
1
@CokoBW Czy to jest stackoverflow.com/questions/10507737/ ... ? naprawdę? Wydaje mi się, że to nie jest zepsute ...
Felipe Sabino
20

Możesz użyć jQuery, aby wykonać POST dla wszystkich swoich przycisków. Po prostu nadaj im tę samą nazwę CssClass.

Użyj "return false;" na końcu zdarzenia javascript onclick, jeśli chcesz wykonać po stronie serwera RedirectToAction po poście, w przeciwnym razie po prostu zwróć widok.

Razor Code

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

Kod JQuery

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

DO#

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

    return RedirectToAction("Index");
    //return View(model);
}
Idris
źródło
@ goodies4uall Rzeczywiście, i ta odpowiedź właśnie to robi. :) Klasa CSS nosi nazwę „saveButton” (być może jest to myląca nazwa), ale do zainicjowania działania używany jest tag kotwicy
Savantes
18

@Aidos miał właściwą odpowiedź, po prostu chciał ją wyjaśnić, ponieważ jest ona ukryta w komentarzu do jego postu opublikowanego przez @CodingWithSpike.

@Ajax.ActionLink("Delete", "Delete", new { id = item.ApkModelId }, new AjaxOptions { HttpMethod = "POST" })
goodies4uall
źródło
6

Oto odpowiedź wypieczona w domyślnym projekcie ASP.NET MVC 5, który, jak sądzę, ładnie realizuje moje cele dotyczące stylizacji w interfejsie użytkownika. Formularz prześlij za pomocą czystego javascript do jakiegoś formularza zawierającego.

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

W pełni pokazany przypadek użycia to menu wylogowania na pasku nawigacyjnym aplikacji internetowej.

@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>
}
daniel.caspers
źródło
3

ActionLink nigdy nie odpali postów. Zawsze wyzwala żądanie GET.

Navish Rampal
źródło
2

Użyj następującego linku Call the Action:

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

Aby przesłać wartości formularza, użyj:

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

Przekaże dane do Kontrolera klienta i CustomerSearchResults Action.

Navish Rampal
źródło
1

Użyj tego linku wewnątrz Ajax.BeginForm

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

;)

Alexey Smolyakov
źródło
1

Moje rozwiązanie tego problemu jest dość proste. Mam stronę, na której klient wyszukuje jeden po całym e-mailu, a drugi po części, częściowo pobiera i wyświetla listę lista ma link do akcji, który wskazuje na wynik działania o nazwie GetByID i przekazuje identyfikator

GetByID pobiera dane dla wybranego klienta, a następnie zwraca

return View("Index", model); 

która jest metodą postu

DJ_PLpłatne
źródło
1

Był to dla mnie trudny problem do rozwiązania. Jak mogę zbudować łącze dynamiczne w maszynce do golenia i html, które może wywołać metodę akcji i przekazać wartość lub wartości do określonej metody akcji? Rozważyłem kilka opcji, w tym niestandardowy pomocnik HTML. Właśnie wymyśliłem proste i eleganckie rozwiązanie.

Widok

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

Metoda działania

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

Chodzi o to, że Url.Action nie dba o to, czy metoda akcji to GET czy POST. Będzie mieć dostęp do dowolnego typu metody. Możesz przekazać swoje dane do metody akcji za pomocą

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

obiekt routeValues. Próbowałem tego i działa. Nie, z technicznego punktu widzenia nie publikujesz postu ani nie przesyłasz formularza, ale jeśli obiekt routeValues ​​zawiera Twoje dane, nie ma znaczenia, czy jest to post, czy get. Aby wybrać właściwą metodę, możesz użyć określonej sygnatury metody akcji.

wayne.blackmon
źródło
1
Wypróbowałem twoją próbkę, a przeglądarka wysyła GET do serwera, nawet formularz ma typ Post. Jeśli actionMethod w kontrolerze ma atrybut [HttpPost] żądanie nie powiedzie się, ponieważ nie znaleziono trasy.
Vitaliy Markitanov
1

Zrobiłem ten sam problem, używając następującego kodu:

@using (Html.BeginForm("Delete", "Admin"))
{
       @Html.Hidden("ProductID", item.ProductID)
       <input type="submit" value="Delete" />
}
isxaker
źródło
Jeśli masz wiele elementów na stronie, będziesz musiał owinąć każdy z nich w formę, w wyniku czego zostanie wygenerowanych wiele formularzy. Również <input type = submit> renderuje przycisk, a nie łącze.
Vitaliy Markitanov
@VitaliyMarkitanov sugerujesz użycie jQuery ajax?
isxaker
Spójrz na mój post poniżej w tym wątku, wyjaśniłem tam moje rozwiązanie.
Vitaliy Markitanov
W przykładowym projekcie MVC jest to dokładnie to, co robią
Maya,
1

To jest moje rozwiązanie problemu. To jest kontroler z 2 metodami akcji

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

W widoku renderuję konstrukcję według następującej struktury.

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

Ciekawe miejsca w Razor View :

  1. Funkcja JavaScript confirmDelete(id)wywoływana po kliknięciu linku wygenerowanego za pomocą @Html.ActionLink;

  2. confirmDelete()funkcja wymaga identyfikatora klikniętego elementu. Ten element jest przekazywany z onClickmodułu obsługi confirmDelete("+feedback.Id+");return false;Zwróć uwagę, że program obsługi zwraca false, aby zapobiec domyślnej akcji - czyli żądaniu odebrania celu. OnClickZdarzenie dla przycisków mogłoby być dołączone z jQuery dla wszystkich przycisków na liście jako alternatywa (prawdopodobnie będzie jeszcze lepiej, ponieważ będzie mniej tekstu na stronie HTML, a dane będą mogły być przekazywane przez data-atrybut).

  3. Formularz ma id=myForm, aby go znaleźć confirmDelete().

  4. Form zawiera @Html.HttpMethodOverride(HttpVerbs.Delete), aby użyć HttpDeleteczasownika, jako czynność oznaczoną znakiem HttpDeleteAttribute.

  5. W funkcji JS używam potwierdzenia akcji (za pomocą zewnętrznej wtyczki, ale standardowe potwierdzenie też działa dobrze. Nie zapomnij użyć bind()w oddzwonieniu lub var that=this(cokolwiek wolisz).

  6. Formularz ma ukryty element z id='idField'i name='id'. Więc zanim formularz zostanie przesłany po potwierdzeniu ( result==true), wartość ukrytego elementu jest ustawiana na argument wartość przekazana, a przeglądarka prześle dane do kontrolera w następujący sposób:

URL żądania :http://localhost:38874/Feedback/Delete

Metoda żądania: Kod stanu POST: 302 znaleziony

Nagłówki odpowiedzi

Lokalizacja: / Host opinii: localhost: 38874 Dane formularza X-HTTP-Method-Override: DELETE id: 5

Jak widać, jest to żądanie POST z X-HTTP-Method-Override: DELETE i danymi w treści ustawionymi na „id: 5”. Odpowiedź zawiera kod 302, który przekierowuje do akcji Index, dzięki czemu po usunięciu odświeżasz ekran.

Vitaliy Markitanov
źródło
0

Poleciłbym pozostać czystym zgodnie z zasadami REST i używać usuwania HTTP do usuwania. Niestety specyfikacje HTML zawierają tylko HTTP Get & Post. Tag może tylko Get HTTP. Znacznik formularza może wykonywać polecenia HTTP Get lub Post. Na szczęście, jeśli używasz Ajax, możesz wykonać HTTP Delete i to właśnie zalecam. Szczegółowe informacje można znaleźć w następującym poście: Http Deletes

coding4fun
źródło
0

Wywołanie $ .post () nie zadziała, ponieważ jest oparte na Ajax. Dlatego do tego celu należy zastosować metodę hybrydową.

Oto rozwiązanie, które działa dla mnie.

Kroki: 1. Utwórz adres URL dla href, który wywoła metodę z adresem URL i parametrem 2. Wywołaj normalny POST za pomocą metody JavaScript

Rozwiązanie:

W .cshtml:

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

Uwaga: metoda anonimowa powinna być opakowana w (....) () tj

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

postGo jest zdefiniowane jak poniżej w JavaScript. Reszta jest prosta ...

@ Url.Action ("Widok") tworzy adres URL połączenia

{'id': @ receiver.ReceiptId} tworzy parametry jako obiekt, który z kolei jest konwertowany na pola POST metodą postGo. Może to być dowolny parametr, jakiego potrzebujesz

W 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);

Referencyjne adresy URL, których użyłem do postGo

GET / POST bez AJAX przy użyciu jQuery (wtyczka?)

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

Tejasvi Hegde
źródło
0

jQuery.post()będzie działać, jeśli masz niestandardowe dane. Jeśli chcesz opublikować istniejący formularz, jest łatwiejszy w użyciu ajaxSubmit().

I nie musisz konfigurować tego kodu w samym ActionLinksobie, ponieważ możesz dołączyć obsługę linku w document.ready()zdarzeniu (co i tak jest preferowaną metodą), na przykład za pomocą $(function(){ ... })triku jQuery.

królowa3
źródło
0

Przeszedłem przez to wymagając POST ze strony wyszukiwania (indeksu) na stronę wyników. Nie potrzebowałem tak dużo, jak stwierdził @Vitaliy, ale wskazało mi to właściwy kierunek. Wszystko, co musiałem zrobić, to:

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

Mój kontroler miał następującą metodę podpisu:

[HttpPost]
public async Task<ActionResult> Result(string k)
Grandizer
źródło
0

Jest to pobierane z przykładowego projektu 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>
            }
        }
Maya
źródło