ASP.NET MVC ActionLink e método post

97

Alguém pode me dizer como posso enviar valores para o controlador usando o método ActionLink e POST?
Não quero usar botões.
Eu acho que tem algo com jquery.

šljaker
fonte
1
Eu escrevi um método semelhante ao Html.ActionLink, só que cria um formulário POST com o botão Enviar. Vou ver se posso dar a opção de substituir o botão pelo link que envia o formulário. Veja aqui: stackoverflow.com/questions/3449807/…
nikib3ro

Respostas:

58

Você não pode usar um ActionLinkporque isso apenas renderiza uma <a>tag âncora .
Você pode usar uma postagem jQuery AJAX .
Ou apenas chame o método de envio do formulário com ou sem jQuery (que seria não-AJAX), talvez no onclickcaso de qualquer controle que desejar.

AUSteve
fonte
70

Se você estiver usando ASP MVC3, poderá usar um Ajax.ActionLink (), que permite especificar um método HTTP que pode ser definido como "POST".

Aidos
fonte
45
Observe que para fazer isso funcionar, você terá que incluir um dos arquivos javascript ajax, por exemplo " jquery.unobtrusive-ajax.min.js". Caso contrário, ele continuará a fazer um GET em vez de um POST quando clicado. A sintaxe para fazer o link seria a seguinte:@Ajax.ActionLink("Delete", "Delete", new { id = item.Id }, new AjaxOptions {HttpMethod = "POST"})
CodingWithSpike
1
Ajax discreto funcionou bem, MAS eu tive que usar o link de ação um pouco diferente, passando um Dicionário como parâmetro em vez deste objeto AjaxOptions: stackoverflow.com/a/10657891/429521 Além disso, eu tive que passar os atributos de ajax manualmente para que o JS poderia capturar e substituir os eventos de clique, eles eram "data-ajax"="true, "data-ajax-url"=<your link> and "data-ajax-method"="Post". A propósito, estou usando ASP.NET MVC 3
Felipe Sabino
1
@CokoBWare este stackoverflow.com/questions/10507737/… ? realmente? Não parece estar quebrado para mim ...
Felipe Sabino
20

Você pode usar o jQuery para fazer um POST para todos os seus botões. Basta dar a eles o mesmo nome CssClass.

Use "return false;" no final do seu evento onclick javascript, se você quiser fazer um RedirectToAction do lado do servidor após a postagem, caso contrário, basta retornar a visualização.

Código de navalha

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

Código 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);
}
Idris
fonte
@ goodies4uall Na verdade, e essa resposta faz exatamente isso. :) A classe CSS é chamada de "saveButton" (talvez um nome enganoso), mas uma tag âncora é usada para iniciar a ação
Savantes
17

A @Aidos deu a resposta certa, só queria deixar bem claro, já que está oculta dentro de um comentário em sua postagem feito por @CodingWithSpike.

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

Aqui está uma resposta embutida no projeto padrão da ASP.NET MVC 5 que acredito que cumpre meus objetivos de estilo muito bem na IU. Envie o formulário usando puro javascript para algum formulário que o contém.

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

O caso de uso totalmente mostrado é uma lista suspensa de logout na barra de navegação de um aplicativo da 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>
}
daniel.caspers
fonte
3

ActionLink nunca disparará postagem. Ele sempre aciona a solicitação GET.

Navish Rampal
fonte
2

Use o seguinte link de chamada de ação:

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

Para enviar os valores do formulário, use:

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

Ele enviará os dados ao controlador do cliente e à ação CustomerSearchResults.

Navish Rampal
fonte
1

Use este link dentro de 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
fonte
1

Minha solução para este problema é bastante simples. Eu tenho uma página que faz uma busca do cliente um pelo e-mail inteiro e outro pelo parcial, o parcial puxa e exibe uma lista a lista tem um link de ação que aponta para um resultado de ação chamado GetByID e passa o id

o GetByID extrai os dados do cliente selecionado e retorna

return View("Index", model); 

qual é o método post

DJ_PLaying
fonte
1

Este tem sido um problema difícil de resolver. Como posso construir um link dinâmico em razor e html que pode chamar um método de ação e passar um valor ou valores para um método de ação específico? Considerei várias opções, incluindo um auxiliar de html personalizado. Acabei de encontrar uma solução simples e elegante.

A vista

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

O método de ação

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

O ponto aqui é que Url.Action não se importa se o método de ação é GET ou POST. Ele acessará qualquer tipo de método. Você pode passar seus dados para o método de ação usando

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

o objeto routeValues. Eu tentei isso e funciona. Não, você não está tecnicamente fazendo uma postagem ou enviando o formulário, mas se o objeto routeValues ​​contiver seus dados, não importa se é uma postagem ou um get. Você pode usar uma assinatura de método de ação específica para selecionar o método correto.

wayne.blackmon
fonte
1
Experimentei seu exemplo e o navegador manda GET para o servidor, mesmo form tem tipo Post. Se actionMethod no controlador tiver atributo [HttpPost], a solicitação falha porque a rota não foi encontrada.
Vitaliy Markitanov
1

Eu fiz o mesmo problema usando o seguinte código:

@using (Html.BeginForm("Delete", "Admin"))
{
       @Html.Hidden("ProductID", item.ProductID)
       <input type="submit" value="Delete" />
}
isxaker
fonte
Se você tiver muitos itens na página, precisará agrupar cada um deles em um formulário e, como resultado, muitos formulários serão gerados. Além disso, <input type = submit> renderiza o botão, não o link.
Vitaliy Markitanov
@VitaliyMarkitanov, você sugere o uso do jQuery ajax?
isxaker
Olhe meu post abaixo neste tópico, eu expliquei minha solução lá.
Vitaliy Markitanov
No projeto de amostra MVC, isso é exatamente o que eles fazem também
Maya
1

Esta é a minha solução para o problema. Este é o controlador com 2 métodos de ação

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

Em View, eu renderizo a construção seguindo a estrutura.

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

Ponto de interesse no Razor View :

  1. Função JavaScript confirmDelete(id)que é chamada quando o link gerado com @Html.ActionLinké clicado;

  2. confirmDelete()função necessária id do item que está sendo clicado. Este item é passado do onClickmanipulador confirmDelete("+feedback.Id+");return false;Preste atenção que o manipulador retorna falso para evitar a ação padrão - que é obter a solicitação para o destino. OnClickO evento para botões pode ser anexado com jQuery para todos os botões da lista como alternativa (provavelmente será ainda melhor, pois haverá menos texto na página HTML e os dados poderão ser passados ​​via data-atributo).

  3. O formulário tem id=myForm, para encontrá-lo em confirmDelete().

  4. A forma inclui @Html.HttpMethodOverride(HttpVerbs.Delete)para usar o HttpDeleteverbo, como ação marcada com o HttpDeleteAttribute.

  5. Na função JS eu uso a confirmação de ação (com ajuda de um plugin externo, mas a confirmação padrão também funciona. Não se esqueça de usar bind()em call back ou var that=this(o que você preferir).

  6. O formulário possui um elemento oculto com id='idField'e name='id'. Portanto, antes que o formulário seja enviado após a confirmação ( result==true), o valor do elemento oculto é definido como o argumento valor passado e o navegador enviará os dados ao controlador como este:

URL do pedido :http://localhost:38874/Feedback/Delete

Método de solicitação : Código de status POST: 302 encontrado

Cabeçalhos de resposta

Localização: / Feedback Host: localhost: 38874 Form Data X-HTTP-Method-Override: DELETE id: 5

Como você pode ver, é uma solicitação POST com X-HTTP-Method-Override: DELETE e os dados no corpo definidos como "id: 5". A resposta tem 302 código que redireciona para a ação de índice, por isso você atualiza sua tela após a exclusão.

Vitaliy Markitanov
fonte
0

Eu recomendaria permanecer puro para os princípios REST e usar uma exclusão HTTP para suas exclusões. Infelizmente, as especificações HTML têm apenas HTTP Get & Post. Uma tag só pode ser HTTP Get. Uma tag de formulário pode fazer um HTTP Get ou Post. Felizmente, se você usar ajax, poderá fazer um HTTP Delete e é isso que eu recomendo. Veja a seguinte postagem para obter detalhes: Http Deletes

coding4fun
fonte
0

Chamar $ .post () não funcionará porque é baseado em Ajax. Portanto, um método híbrido precisa ser usado para esse propósito.

A seguir está a solução que está funcionando para mim.

Passos: 1. Crie URL para href que chama o método a com url e parâmetro 2. Chame POST normal usando o método JavaScript

Solução:

Em .cshtml:

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

Nota: o método anônimo deve ser delimitado por (....) (), ou seja,

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

postGo é definido como abaixo em JavaScript. O descanso é simples ..

@ Url.Action ("View") cria url para a chamada

{'id': @ recibo.ReceiptId} cria parâmetros como objeto que por sua vez é convertido em campos POST no método postGo. Pode ser qualquer parâmetro que você precisar

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

URLs de referência que usei para postGo

GET / POST não ajax usando jQuery (plugin?)

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

Tejasvi Hegde
fonte
0

jQuery.post()funcionará se você tiver dados personalizados. Se você quiser postar um formulário existente, é mais fácil de usar ajaxSubmit().

E você não precisa configurar esse código em ActionLinksi, já que pode anexar um manipulador de link no document.ready()evento (que é o método preferido de qualquer maneira), por exemplo, usando o $(function(){ ... })truque jQuery.

queen3
fonte
0

Deparei com a necessidade de POSTAR de uma página de pesquisa (índice) para a página de resultados. Não precisei de tanto quanto @Vitaliy declarou, mas me apontou na direção certa. Tudo que eu tive que fazer foi isto:

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

Meu controlador tinha o seguinte método de assinatura:

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

Isso é retirado do projeto de amostra 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>
            }
        }
Maia
fonte