Jak obsługiwać wiele przycisków submit w ASP.NET MVC Framework?

Czy Jest jakiś łatwy sposób na obsługę wielu przycisków wyślij z tego samego formularza? Na przykład:

<% Html.BeginForm("MyAction", "MyController", FormMethod.Post); %>
<input type="submit" value="Send" />
<input type="submit" value="Cancel" />
<% Html.EndForm(); %>

Jakiś pomysł jak to zrobić w ASP.NET Framework Beta? Wszystkie przykłady, które googlowałem, mają w sobie pojedyncze przyciski.

Author: iliketocode, 2009-01-14

30 answers

Oto w większości czyste rozwiązanie oparte na atrybutach problemu z przyciskiem wielokrotnego przesyłania oparte w dużej mierze na poście i komentarzach z Maartena Balliauw .

[AttributeUsage(AttributeTargets.Method, AllowMultiple = false, Inherited = true)]
public class MultipleButtonAttribute : ActionNameSelectorAttribute
{
    public string Name { get; set; }
    public string Argument { get; set; }

    public override bool IsValidName(ControllerContext controllerContext, string actionName, MethodInfo methodInfo)
    {
        var isValidName = false;
        var keyValue = string.Format("{0}:{1}", Name, Argument);
        var value = controllerContext.Controller.ValueProvider.GetValue(keyValue);

        if (value != null)
        {
            controllerContext.Controller.ControllerContext.RouteData.Values[Name] = Argument;
            isValidName = true;
        }

        return isValidName;
    }
}

Razor:

<form action="" method="post">
 <input type="submit" value="Save" name="action:Save" />
 <input type="submit" value="Cancel" name="action:Cancel" />
</form>

I kontroler:

[HttpPost]
[MultipleButton(Name = "action", Argument = "Save")]
public ActionResult Save(MessageModel mm) { ... }

[HttpPost]
[MultipleButton(Name = "action", Argument = "Cancel")]
public ActionResult Cancel(MessageModel mm) { ... }

Aktualizacja: Strona Razor pages wygląda na taką samą funkcjonalność po wyjęciu z pudełka. W przypadku nowego rozwoju może to być lepsze.

 644
Author: mkozicki,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2019-10-29 08:53:35

Nadaj przyciskom submit nazwę, a następnie sprawdź przesłaną wartość w metodzie kontrolera:

<% Html.BeginForm("MyAction", "MyController", FormMethod.Post); %>
<input type="submit" name="submitButton" value="Send" />
<input type="submit" name="submitButton" value="Cancel" />
<% Html.EndForm(); %>

Wysłanie do

public class MyController : Controller {
    public ActionResult MyAction(string submitButton) {
        switch(submitButton) {
            case "Send":
                // delegate sending to another controller action
                return(Send());
            case "Cancel":
                // call another action to perform the cancellation
                return(Cancel());
            default:
                // If they've submitted the form without a submitButton, 
                // just return the view again.
                return(View());
        }
    }

    private ActionResult Cancel() {
        // process the cancellation request here.
        return(View("Cancelled"));
    }

    private ActionResult Send() {
        // perform the actual send operation here.
        return(View("SendConfirmed"));
    }

}

EDIT:

Aby rozszerzyć to podejście do pracy z lokalizowanymi witrynami, Wyizoluj swoje wiadomości gdzie indziej (np. kompilując plik zasobów do silnie wpisanej klasy zasobów)

Następnie zmodyfikuj kod tak, aby działał tak:

<% Html.BeginForm("MyAction", "MyController", FormMethod.Post); %>
<input type="submit" name="submitButton" value="<%= Html.Encode(Resources.Messages.Send)%>" />
<input type="submit" name="submitButton" value="<%=Html.Encode(Resources.Messages.Cancel)%>" />
<% Html.EndForm(); %>

A twój kontroler powinien wyglądać tak:

// Note that the localized resources aren't constants, so 
// we can't use a switch statement.

if (submitButton == Resources.Messages.Send) { 
    // delegate sending to another controller action
    return(Send());

} else if (submitButton == Resources.Messages.Cancel) {
     // call another action to perform the cancellation
     return(Cancel());
}
 472
Author: Dylan Beattie,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2010-11-03 11:37:50

Możesz sprawdzić nazwę w akcji, jak już wspomniano, ale możesz rozważyć, czy jest to dobry projekt. Dobrze jest wziąć pod uwagę odpowiedzialność działania i nie łączyć tego projektu zbytnio z aspektami interfejsu, takimi jak nazwy przycisków. Rozważmy więc użycie 2 form i 2 działań:

<% Html.BeginForm("Send", "MyController", FormMethod.Post); %>
<input type="submit" name="button" value="Send" />
<% Html.EndForm(); %>

<% Html.BeginForm("Cancel", "MyController", FormMethod.Post); %>
<input type="submit" name="button" value="Cancel" />
<% Html.EndForm(); %>

Również, w przypadku "Anuluj", zwykle po prostu nie przetwarzasz formularza i przechodzisz do nowego adresu URL. W takim przypadku nie musisz w ogóle przesyłać formularza i po prostu potrzebujesz link:

<%=Html.ActionLink("Cancel", "List", "MyController") %>
 121
Author: Trevor de Koekkoek,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2009-01-14 12:26:26

Eilon sugeruje, że możesz to zrobić tak:

Jeśli masz więcej niż jeden przycisk, możesz można je odróżnić, dając każdy przycisk a nazwa:

<input type="submit" name="SaveButton" value="Save data" />
<input type="submit" name="CancelButton" value="Cancel and go back to main page" />

W metodzie działania kontrolera można można dodać parametry nazwane po Nazwy znaczników wejściowych HTML:

public ActionResult DoSomeStuff(string saveButton, string
cancelButton, ... other parameters ...)
{ ... }

Jeśli jakakolwiek wartość zostanie wysłana do jednego z te parametry, to znaczy, że przycisk był tym, który został kliknięty. Przeglądarka internetowa zamieści tylko wartość dla jednego przycisku, który został kliknięty. Wszystkie inne wartości będą null.

if (saveButton != null) { /* do save logic */ }
if (cancelButton != null) { /* do cancel logic */ }

Podoba mi się ta metoda, ponieważ nie opiera się na właściwości value przycisków submit, które są bardziej prawdopodobne, aby zmienić niż przypisane nazwy i nie wymaga włączania javascript

Zobacz: http://forums.asp.net/p/1369617/2865166.aspx#2865166

 102
Author: PabloBlamirez,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2009-01-21 16:51:12

Właśnie napisałem post o tym: wiele przycisków submit z ASP.NET MVC :

W zasadzie zamiast używać ActionMethodSelectorAttribute, używam ActionNameSelectorAttribute, co pozwala mi udawać, że nazwa akcji jest tym, czym chcę, aby była. Na szczęście ActionNameSelectorAttribute nie tylko każe mi podać nazwę akcji, ale mogę wybrać, czy bieżąca akcja pasuje do żądania.

Więc jest moja klasa (btw nie przepadam za nazwą):

public class HttpParamActionAttribute : ActionNameSelectorAttribute {
    public override bool IsValidName(ControllerContext controllerContext, string actionName, MethodInfo methodInfo) {
        if (actionName.Equals(methodInfo.Name, StringComparison.InvariantCultureIgnoreCase))
            return true;

        if (!actionName.Equals("Action", StringComparison.InvariantCultureIgnoreCase))
            return false;

        var request = controllerContext.RequestContext.HttpContext.Request;
        return request[methodInfo.Name] != null;
    }
} 

Aby użyć po prostu określ formę jak to:

<% using (Html.BeginForm("Action", "Post")) { %>
  <!— …form fields… -->
  <input type="submit" name="saveDraft" value="Save Draft" />
  <input type="submit" name="publish" value="Publish" />
<% } %> 

I kontroler z dwoma metodami

public class PostController : Controller {
    [HttpParamAction]
    [AcceptVerbs(HttpVerbs.Post)]
    public ActionResult SaveDraft(…) {
        //…
    }

    [HttpParamAction]
    [AcceptVerbs(HttpVerbs.Post)]
    public ActionResult Publish(…) {
        //…
    } 
}

Jak widzisz, atrybut nie wymaga od Ciebie podawania czegokolwiek. Ponadto nazwy przycisków są tłumaczone bezpośrednio na nazwy metod. Dodatkowo (nie próbowałem tego) powinny one działać również jako normalne działania, więc możesz pisać do dowolnego z nich bezpośrednio.

 45
Author: Andrey Shchekin,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2013-07-18 03:05:38

Jest krótki i prosty:

Odpowiedział Jeroen Dop

<input type="submit" name="submitbutton1" value="submit1" />
<input type="submit" name="submitbutton2" value="submit2" />

I zrób tak w kodzie behinde

 if( Request.Form["submitbutton1"] != null)
{
    // Code for function 1
}
else if(Request.Form["submitButton2"] != null )
{
       // code for function 2
}
Powodzenia.
 37
Author: Ali Gol Gol,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2017-05-23 12:18:25

Proponowałbym zainteresowanym stronom przyjrzeć się rozwiązaniu Maartena Balliauwa [3]. Myślę, że jest bardzo elegancki.

W przypadku, gdy łącze zniknie, używa atrybutu MultiButton zastosowanego do akcji kontrolera, aby wskazać, do którego przycisku powinno się odnosić kliknięcie tej akcji.

 35
Author: Izmoto,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2017-02-16 00:33:01

Powinno być możliwe nazwanie przycisków i nadanie im wartości; następnie mapowanie tej nazwy jako argumentu do akcji. Alternatywnie, użyj 2 oddzielnych linków akcji lub 2 formularzy.

 21
Author: Marc Gravell,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2009-01-14 12:07:05

Możesz napisać:

<% Html.BeginForm("MyAction", "MyController", FormMethod.Post); %>
<input type="submit" name="button" value="Send" />
<input type="submit" name="button" value="Cancel" />
<% Html.EndForm(); %>

A następnie na stronie sprawdź, czy nazwa = = "Wyślij" lub nazwa = = "Anuluj"...

 14
Author: Ironicnet,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2010-08-13 12:39:59

Coś, co nie podoba mi się w ActionSelectName, to to, że IsValidName jest wywoływane dla każdej metody akcji w kontrolerze; Nie wiem, dlaczego tak działa. Podoba mi się rozwiązanie, w którym każdy przycisk ma inną nazwę w zależności od tego, co robi, ale nie podoba mi się fakt, że musisz mieć tyle parametrów w metodzie akcji, ile przycisków w formularzu. Stworzyłem enum dla wszystkich typów przycisków:

public enum ButtonType
{
    Submit,
    Cancel,
    Delete
}

Zamiast ActionSelectName, używam filtra ActionFilter:

public class MultipleButtonsEnumAttribute : ActionFilterAttribute
{
    public Type EnumType { get; set; }

    public MultipleButtonsEnumAttribute(Type enumType)
    {
        EnumType = enumType;
    }

    public override void OnActionExecuting(ActionExecutingContext filterContext)
    {
        foreach (var key in filterContext.HttpContext.Request.Form.AllKeys)
        {
            if (Enum.IsDefined(EnumType, key))
            {
                var pDesc = filterContext.ActionDescriptor.GetParameters()
                    .FirstOrDefault(x => x.ParameterType == EnumType);
                filterContext.ActionParameters[pDesc.ParameterName] = Enum.Parse(EnumType, key);
                break;
            }
        }
    }
}

Filtr znajdzie nazwę przycisku w danych formularza i jeśli nazwa przycisku pasuje do dowolnego z typów przycisków zdefiniowanych w enum, znajdzie parametr ButtonType wśród parametrów akcji:

[MultipleButtonsEnumAttribute(typeof(ButtonType))]
public ActionResult Manage(ButtonType buttonPressed, ManageViewModel model)
{
    if (button == ButtonType.Cancel)
    {
        return RedirectToAction("Index", "Home");
    }
    //and so on
    return View(model)
}

A potem w widokach mogę użyć:

<input type="submit" value="Button Cancel" name="@ButtonType.Cancel" />
<input type="submit" value="Button Submit" name="@ButtonType.Submit" />
 12
Author: sanjuro,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2014-12-05 17:56:02

Oto co dla mnie najlepsze:

<input type="submit" value="Delete" name="onDelete" />
<input type="submit" value="Save" name="onSave" />


public ActionResult Practice(MyModel model, string onSave, string onDelete)
{
    if (onDelete != null)
    {
        // Delete the object
        ...
        return EmptyResult();
    }

    // Save the object
    ...
    return EmptyResult();
}
 11
Author: Sergey,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2011-12-22 00:46:25

Natknąłem się również na ten "problem", ale znalazłem raczej logiczne rozwiązanie, dodając atrybut name. Nie mogłem sobie przypomnieć, że ten problem występuje w innych językach.

Http://www.w3.org/TR/html401/interact/forms.html#h-17.13.2

  • ...
  • Jeśli formularz zawiera więcej niż jeden przycisk Wyślij, tylko aktywowany przycisk Wyślij jest pomyślny.
  • ...

Czyli następujący kod value atrybuty mogą być zmieniane, zlokalizowane, Internacjonalizacja bez potrzeba do dodatkowego sprawdzania kodu mocno wpisanych plików zasobów lub stałych.

<% Html.BeginForm("MyAction", "MyController", FormMethod.Post); %>
<input type="submit" name="send" value="Send" />
<input type="submit" name="cancel" value="Cancel" />
<input type="submit" name="draft" value="Save as draft" />
<% Html.EndForm(); %>`

Po stronie odbiorczej musisz tylko sprawdzić, czy któryś z Twoich znanych typów submit nie jest null

public ActionResult YourAction(YourModel model) {

    if(Request["send"] != null) {

        // we got a send

    }else if(Request["cancel"]) {

        // we got a cancel, but would you really want to post data for this?

    }else if(Request["draft"]) {

        // we got a draft

    }

}
 11
Author: Tom Hofman,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2015-01-09 09:42:01

Jeśli nie masz ograniczeń co do korzystania z HTML 5, możesz użyć znacznika <button> z atrybutem formaction:

<form action="demo_form.asp" method="get">
   First name: <input type="text" name="fname" /><br />
   Last name: <input type="text" name="lname" /><br />
   <button type="submit">Submit</button><br />
   <button type="submit" formaction="demo_admin.asp">Submit as admin</button>
</form>

Odniesienie: http://www.w3schools.com/html5/att_button_formaction.asp

 10
Author: Acaz Souza,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2011-11-08 10:51:02

Jeśli twoja przeglądarka obsługuje atrybut formaction dla przycisków wejściowych (tj.]}

@using (Html.BeginForm()){
    //put form inputs here

<input id="sendBtn" value="Send" type="submit" formaction="@Url.Action("Name Of Send Action")" />

<input id="cancelBtn" value="Cancel" type="submit" formaction="@Url.Action("Name of Cancel Action") />

}
 10
Author: user3361233,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2014-02-27 15:44:12

Istnieją trzy sposoby rozwiązania powyższego problemu

  1. HTML way
  2. jQuery way
  3. "ActionNameSelectorAttribute" sposób

Poniżej znajduje się film podsumowujący wszystkie trzy podejścia w demonstracyjny sposób.

Https://www.facebook.com/shivprasad.koirala/videos/vb.100002224977742/809335512483940

HTML way :-

W HTML sposób musimy utworzyć dwa formularze i umieścić przycisk "Submit" wewnątrz każda z form. I każda forma działania będzie wskazywać na różne / odpowiednie działania. Możesz zobaczyć poniższy kod, który pierwszy formularz jest wysyłany do "Action1", a drugi formularz będzie wysyłany do " Action2 "w zależności od kliknięcia przycisku" Wyślij".

<form action="Action1" method=post>
<input type=”submit” name=”Submit1”/>
</form>

<form action="Action2" method=post>
<input type=”submit” name=”Submit2”>
</form>

Ajax way :-

W przypadku, gdy jesteś miłośnikiem Ajax ta druga opcja podnieci Cię bardziej. W Ajax sposób możemy stworzyć dwie różne funkcje "Fun1" i "Fun1", patrz poniższy kod. Te funkcje sprawią, że Ajax wywołania za pomocą JQUERY lub innego frameworka. Każda z tych funkcji jest powiązana ze zdarzeniami" onclick "przycisku " Submit". Każda z tych funkcji wywołuje odpowiednie nazwy akcji.

<Script language="javascript">
function Fun1()
{
$.post(“/Action1”,null,CallBack1);
}
function Fun2()
{
$.post(“/Action2”,null,CallBack2);
}
</Script>

<form action="/Action1" method=post>
<input type=submit name=sub1 onclick=”Fun2()”/>
</form>
<form action="/Action2" method=post>
<input type=submit name=sub2 onclick=”Fun1()”/>
</form>

Korzystanie Z "ActionNameSelectorAttribute":-

To świetna i czysta opcja. "ActionNameSelectorAttribute" jest prostą klasą atrybutów, w której możemy napisać logikę podejmowania decyzji, która zadecyduje, która akcja może zostać wykonana.

Więc pierwszą rzeczą jest w HTML my trzeba umieścić odpowiednią nazwę do przycisków submit do identyfikacji ich na serwerze.

Widać, że dodaliśmy "Zapisz" i "usuń" do nazw przycisków. Możesz również zauważyć, że w akcji właśnie umieściliśmy nazwę kontrolera "klient", a nie konkretną nazwę akcji. Spodziewamy się, że o nazwie akcji zadecyduje "ActionNameSelectorAttribute".

<form action=”Customer” method=post>
<input type=submit value="Save" name="Save" /> <br />
<input type=submit value="Delete" name="Delete"/>
</form>

Więc po kliknięciu przycisku submit, najpierw trafia atrybut "ActionNameSelector", a następnie w zależności od tego, który przycisk submit zostanie wywołany powołuje się na odpowiednie działanie.

Tutaj wpisz opis obrazka

Więc pierwszym krokiem jest utworzenie klasy, która dziedziczy z klasy "ActionNameSelectorAttribute". W tej klasie stworzyliśmy prostą właściwość "Name".

Musimy również nadpisać funkcję "IsValidName", która zwraca true lub flase. W tej funkcji zapisujemy logikę, czy dana akcja ma być wykonana, czy nie. Więc jeśli ta funkcja zwraca true, wtedy akcja jest wykonywana lub nie jest.

public class SubmitButtonSelector : ActionNameSelectorAttribute
    {
        public string Name { get; set; }
        public override bool IsValidName(ControllerContext controllerContext, string actionName, System.Reflection.MethodInfo methodInfo)
        {
            // Try to find out if the name exists in the data sent from form
var value = controllerContext.Controller.ValueProvider.GetValue(Name);
            if (value != null)
            {
                return true;
            }
            return false;

        }
    }

The główne serce powyższej funkcji znajduje się w poniższym kodzie. Kolekcja "ValueProvider" zawiera wszystkie dane, które zostały opublikowane z formularza. Więc najpierw wyszukuje wartość "Name" i jeśli jej znaleziono w żądaniu HTTP zwraca true lub false.

var value = controllerContext.Controller.ValueProvider.GetValue(Name);
if (value != null)
      {
        return true;
      }
      return false;

Ta klasa atrybutów może być następnie udekorowana odpowiednią akcją i można podać odpowiednią wartość "Name". Więc jeśli submit uderza w tę akcję i jeśli nazwa pasuje do przycisku Wyślij HTML, nazwij go wtedy wykonuje akcję dalej lub nie.

public class CustomerController : Controller
{
        [SubmitButtonSelector(Name="Save")]
        public ActionResult Save()
        {
            return Content("Save Called");
        }
        [SubmitButtonSelector(Name = "Delete")]
        public ActionResult Delete()
        {
            return Content("Delete Called");
        }
}
 9
Author: Shivprasad Koirala,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2015-05-21 03:29:27

David Findley pisze o 3 różnych opcjach, które masz do tego, na jego ASP.Net weblog.

Przeczytaj artykuł wiele przycisków w tej samej formie , aby zobaczyć jego rozwiązania oraz zalety i wady każdego z nich. IMHO zapewnia bardzo eleganckie rozwiązanie, które wykorzystuje atrybuty, którymi udekorujesz swoją akcję.

 7
Author: Saajid Ismail,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2009-06-26 09:35:26

To jest technika, której bym użył i jeszcze jej tu nie widzę. Link (wysłany przez Saajid Ismail ), które inspiruje To rozwiązanie jest http://weblogs.asp.net/dfindley/archive/2009/05/31/asp-net-mvc-multiple-buttons-in-the-same-form.aspx). dostosowuje odpowiedź Dylan Beattie zrobić lokalizację bez żadnych problemów.

W widoku:

<% Html.BeginForm("MyAction", "MyController", FormMethod.Post); %>
<button name="button" value="send"><%: Resources.Messages.Send %></button>
<button name="button" value="cancel"><%: Resources.Messages.Cancel %></button>
<% Html.EndForm(); %>

W kontrolerze:

public class MyController : Controller 
{
    public ActionResult MyAction(string button)
    {
         switch(button)
         {
             case "send":
                 this.DoSend();
                 break;
             case "cancel":
                 this.DoCancel();
                 break;
         }
    }
}
 7
Author: mlibby,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2010-11-01 21:20:29

Ten skrypt pozwala określić atrybut data-form-action, który będzie działał jako atrybut FORMACTION HTML5 we wszystkich przeglądarkach (w sposób dyskretny):

$(document).on('click', '[type="submit"][data-form-action]', function(event) {
    var $this = $(this),
    var formAction = $this.attr('data-form-action'),
    $form = $($this.closest('form'));
    $form.attr('action', formAction);             
});

Formularz zawierający przycisk zostanie wysłany na adres URL podany w atrybucie data-form-action:

<button type="submit" data-form-action="different/url">Submit</button>   

To wymaga jQuery 1.7. W przypadku poprzednich wersji należy użyć live() zamiast on().

 7
Author: Jay Douglass,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2013-05-16 12:16:50
[HttpPost]
public ActionResult ConfirmMobile(string nameValueResend, string nameValueSubmit, RegisterModel model)
    {
        var button = nameValueResend ?? nameValueSubmit;
        if (button == "Resend")
        {

        }
        else
        {

        }
    }


    Razor file Content:
    @using (Html.BeginForm()
    {
        <div class="page registration-result-page">

            <div class="page-title">
                <h1> Confirm Mobile Number</h1>
            </div>

            <div class="result">
                @Html.EditorFor(model => model.VefificationCode)
                @Html.LabelFor(model => model.VefificationCode, new { })
                @Html.ValidationMessageFor(model => model.VefificationCode)
            </div>
            <div class="buttons">
                <button type="submit" class="btn" name="nameValueResend" value="Resend">
                    Resend
                </button>
                <button type="submit" class="btn" name="nameValueSubmit" value="Verify">
                    Submit
                </button>

            </div>
            </div>

    }
 7
Author: Mahendra,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2018-01-30 14:50:07

Oto metoda rozszerzenia, którą napisałem, aby obsługiwać wiele przycisków graficznych i / lub tekstowych.

Oto kod HTML dla przycisku obrazka:

<input id="btnJoin" name="Join" src="/content/images/buttons/btnJoin.png" 
       type="image">

Lub dla przycisku Wyślij tekst:

<input type="submit" class="ui-button green" name="Submit_Join" value="Add to cart"  />
<input type="submit" class="ui-button red" name="Submit_Skip" value="Not today"  />

Oto metoda rozszerzenia, którą wywołujesz z kontrolera za pomocą form.GetSubmitButtonName(). W przypadku przycisków obrazu szuka parametru formularza z .x (który wskazuje, że przycisk obrazu został kliknięty) i wyodrębnia nazwę. Dla zwykłych przycisków input wyszukuje nazwę zaczynającą się od Submit_ i wyciąga polecenie od później. Ponieważ wyabstrahuję logikę określania "polecenia" można przełączać się między przyciskami obrazek + tekst na Kliencie bez zmiany kodu po stronie serwera.

public static class FormCollectionExtensions
{
    public static string GetSubmitButtonName(this FormCollection formCollection)
    {
        return GetSubmitButtonName(formCollection, true);
    }

    public static string GetSubmitButtonName(this FormCollection formCollection, bool throwOnError)
    {
        var imageButton = formCollection.Keys.OfType<string>().Where(x => x.EndsWith(".x")).SingleOrDefault();
        var textButton = formCollection.Keys.OfType<string>().Where(x => x.StartsWith("Submit_")).SingleOrDefault();

        if (textButton != null)
        {
            return textButton.Substring("Submit_".Length);
        }

        // we got something like AddToCart.x
        if (imageButton != null)
        {
            return imageButton.Substring(0, imageButton.Length - 2);
        }

        if (throwOnError)
        {
            throw new ApplicationException("No button found");
        }
        else
        {
            return null;
        }
    }
}

Uwaga: w przypadku przycisków tekstowych należy przedrostek nazwy użyć Submit_. Preferuję ten sposób, ponieważ oznacza to, że możesz zmienić wartość tekstową (wyświetl) bez konieczności zmiany kodu. W przeciwieństwie do elementów SELECT, Przycisk INPUT ma tylko "wartość" i nie ma oddzielnego atrybutu "tekst". Moje guziki mówią różne rzeczy w różnych kontekstach - ale mapować do tego samego "polecenia". Zdecydowanie wolę wyodrębnić nazwę w ten sposób niż kodować == "Add to cart".

 6
Author: Simon_Weaver,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2011-02-19 01:52:17

Nie mam wystarczająco dużo reputacji, aby skomentować we właściwym miejscu, ale spędziłem cały dzień na tym, więc chcę się podzielić.

Podczas próby implementacji rozwiązania "MultipleButtonAttribute" ValueProvider.GetValue(keyValue) nieprawidłowo wróci null.

/ Align= "left" / Www.MVC w wersji 3.0, kiedy powinna być 4.0 (inne zespoły to 4.0). Nie wiem, dlaczego mój projekt nie zaktualizował się poprawnie i nie miałem innych oczywistych problemów.

Więc jeśli Twój {[2] } nie działa... sprawdź to.

 6
Author: HeatherD,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2012-12-14 16:19:47

Spóźnię się na imprezę, ale zaczynamy... Moja implementacja zapożycza się z @mkozicki, ale wymaga mniej zakodowanych ciągów, aby się pomylić. Framework 4.5+ wymagane . Zasadniczo nazwa metody kontrolera powinna być kluczem do routingu.

Znaczniki . Nazwa przycisku musi być oznaczona symbolem "action:[controllerMethodName]"

(zwróć uwagę na użycie API C # 6 nameof, dostarczającego odniesienie dla danego typu do nazwy metody kontrolera, którą chcesz / align = "left" /

<form>
    ... form fields ....
    <button name="action:@nameof(MyApp.Controllers.MyController.FundDeathStar)" type="submit" formmethod="post">Fund Death Star</button>
    <button name="action:@nameof(MyApp.Controllers.MyController.HireBoba)" type="submit" formmethod="post">Hire Boba Fett</button>
</form>

Controller :

namespace MyApp.Controllers
{
    class MyController
    {    
        [SubmitActionToThisMethod]
        public async Task<ActionResult> FundDeathStar(ImperialModel model)
        {
            await TrainStormTroopers();
            return View();
        }

        [SubmitActionToThisMethod]
        public async Task<ActionResult> HireBoba(ImperialModel model)
        {
            await RepairSlave1();
            return View();
        }
    }
}

Atrybut Magic . Zwróć uwagę na wykorzystanie CallerMemberName Boże.

[AttributeUsage(AttributeTargets.Method, AllowMultiple = false, Inherited = true)]
public class SubmitActionToThisMethodAttribute : ActionNameSelectorAttribute
{        
    public SubmitActionToThisMethodAttribute([CallerMemberName]string ControllerMethodName = "")
    {
        controllerMethod = ControllerMethodName;
        actionFormat = string.Concat(actionConstant, ":", controllerMethod);
    }
    const string actionConstant = "action";
    readonly string actionFormat;
    readonly string controllerMethod;

    public override bool IsValidName(ControllerContext controllerContext, string actionName, MethodInfo methodInfo)
    {
        var isValidName = false;
        var value = controllerContext.Controller.ValueProvider.GetValue(actionFormat);

        if (value != null)
        {
            controllerContext.Controller.ControllerContext.RouteData.Values[actionConstant] = controllerMethod;
            isValidName = true;
        }
        return isValidName;
    }
}
 6
Author: Aaron Hudon,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2016-10-28 03:06:45

Próbowałem dokonać syntezy wszystkich rozwiązań i stworzyłem atrybut [ButtenHandler], który ułatwia obsługę wielu przycisków w formularzu.

Opisałem to na CodeProject Wiele parametryzowanych (lokalizowalnych) przycisków formularza w ASP.NET MVC .

Aby obsłużyć prosty przypadek tego przycisku:

<button type="submit" name="AddDepartment">Add Department</button>

Będziesz miał coś takiego jak następująca metoda działania:

[ButtonHandler()]
public ActionResult AddDepartment(Company model)
{
    model.Departments.Add(new Department());
    return View(model);
}

Zwróć uwagę, jak nazwa przycisku pasuje do nazwy metody akcji. Na artykuł opisuje również, jak mieć przyciski z wartościami i przyciski z indeksami.

 5
Author: codetuner,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2012-09-26 16:34:26
//model
    public class input_element
        {
         public string Btn { get; set; }
        }   

//views--submit btn can be input type also...
    @using (Html.BeginForm())
    {
            <button type="submit" name="btn" value="verify">
             Verify data</button>
            <button type="submit" name="btn" value="save">
             Save data</button>    
            <button type="submit" name="btn" value="redirect">
                 Redirect</button>
    }

//controller

    public ActionResult About()
        {
            ViewBag.Message = "Your app description page.";
            return View();
        }

        [HttpPost]
        public ActionResult About(input_element model)
        {
                if (model.Btn == "verify")
                {
                // the Verify button was clicked
                }
                else if (model.Btn == "save")
                {
                // the Save button was clicked
                } 
                else if (model.Btn == "redirect")
                {
                // the Redirect button was clicked
                } 
                return View();
        }
 5
Author: SHAURAJ SINGH,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2013-02-26 05:33:10

To jest najlepszy sposób, jaki znalazłem:

Http://iwayneo.blogspot.co.uk/2013/10/aspnet-mvc-action-selector-with-list.html

Oto kod:

    /// <summary>
    /// ActionMethodSelector to enable submit buttons to execute specific action methods.
    /// </summary>
    public class AcceptParameterAttribute : ActionMethodSelectorAttribute
   {
        /// <summary>
        /// Gets or sets the value to use to inject the index into
        /// </summary>
       public string TargetArgument { get; set; }

       /// <summary>
       /// Gets or sets the value to use in submit button to identify which method to select. This must be unique in each controller.
       /// </summary>
       public string Action { get; set; }

       /// <summary>
       /// Gets or sets the regular expression to match the action.
       /// </summary>
       public string ActionRegex { get; set; }

       /// <summary>
       /// Determines whether the action method selection is valid for the specified controller context.
       /// </summary>
       /// <param name="controllerContext">The controller context.</param>
       /// <param name="methodInfo">Information about the action method.</param>
       /// <returns>true if the action method selection is valid for the specified controller context; otherwise, false.</returns>
       public override bool IsValidForRequest(ControllerContext controllerContext, MethodInfo methodInfo)
       {

           if (controllerContext == null)
           {
               throw new ArgumentNullException("controllerContext");
           }

           Func<NameValueCollection> formGetter;
           Func<NameValueCollection> queryStringGetter;

           ValidationUtility.GetUnvalidatedCollections(HttpContext.Current, out formGetter, out queryStringGetter);

           var form = formGetter();
           var queryString = queryStringGetter();

           var req = form.AllKeys.Any() ? form : queryString;

           if (!string.IsNullOrEmpty(this.ActionRegex))
           {
               foreach (var key in req.AllKeys.Where(k => k.StartsWith(Action, true, System.Threading.Thread.CurrentThread.CurrentCulture)))
               {
                   if (key.Contains(":"))
                   {
                       if (key.Split(':').Count() == this.ActionRegex.Split(':').Count())
                       {
                           bool match = false;
                           for (int i = 0; i < key.Split(':').Count(); i++)
                           {
                               if (Regex.IsMatch(key.Split(':')[0], this.ActionRegex.Split(':')[0]))
                               {
                                   match = true;
                               }
                               else
                               {
                                   match = false;
                                   break;
                               }
                           }

                           if (match)
                           {
                               return !string.IsNullOrEmpty(req[key]);
                           }
                       }
                   }
                   else
                   {
                       if (Regex.IsMatch(key, this.Action + this.ActionRegex))
                       {
                           return !string.IsNullOrEmpty(req[key]);
                       }
                   }

               }
               return false;
           }
           else
           {
               return req.AllKeys.Contains(this.Action);
           }
       }
   }

Ciesz się bezzapachowym przyciskiem multi submit future.

Dziękuję

 5
Author: ,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2013-10-28 10:57:58

Zmodyfikowana wersja metody HttpParamActionAttribute, ale z poprawką błędu za nie powodowanie błędu przy wygasłych / nieprawidłowych postach sesji. Aby sprawdzić, czy jest to problem z bieżącą witryną, otwórz formularz w oknie i tuż przed przejściem do Kliknij Save lub Publish, otwórz zduplikowane okno i wyloguj się. Teraz wróć do pierwszego okna i spróbuj przesłać formularz za pomocą dowolnego przycisku. Dla mnie mam błąd, więc ta zmiana rozwiązuje ten problem dla mnie. Pomijam kilka rzeczy dla zwięzłości, ale ty powinien mieć pomysł. Kluczowe części to włączenie ActionName do atrybutu i upewnienie się, że przekazana nazwa jest nazwą widoku, który pokazuje formularz

Klasa Atrybutów

[AttributeUsage(AttributeTargets.Method, AllowMultiple = false, Inherited = true)]
public class HttpParamActionAttribute : ActionNameSelectorAttribute
{
    private readonly string actionName;

    public HttpParamActionAttribute(string actionName)
    {
        this.actionName = actionName;
    }

    public override bool IsValidName(ControllerContext controllerContext, string actionName, MethodInfo methodInfo)
    {
        if (actionName.Equals(methodInfo.Name, StringComparison.InvariantCultureIgnoreCase))
            return true;

        if (!actionName.Equals(this.actionName, StringComparison.InvariantCultureIgnoreCase))
            return false;

        var request = controllerContext.RequestContext.HttpContext.Request;
        return request[methodInfo.Name] != null;
    }
}

Controller

[Authorize(Roles="CanAddContent")]
public ActionResult CreateContent(Guid contentOwnerId)
{
    var viewModel = new ContentViewModel
    {
        ContentOwnerId = contentOwnerId
        //populate rest of view model
    }
    return View("CreateContent", viewModel);
}

[Authorize(Roles="CanAddContent"), HttpPost, HttpParamAction("CreateContent"), ValidateAntiForgeryToken]
public ActionResult SaveDraft(ContentFormModel model)
{
    //Save as draft
    return RedirectToAction("CreateContent");
}

[Authorize(Roles="CanAddContent"), HttpPost, HttpParamAction("CreateContent"), ValidateAntiForgeryToken]
public ActionResult Publish(ContentFormModel model)
{
    //publish content
    return RedirectToAction("CreateContent");
}

Widok

@using (Ajax.BeginForm("CreateContent", "MyController", new { contentOwnerId = Model.ContentOwnerId }))
{
    @Html.AntiForgeryToken()
    @Html.HiddenFor(x => x.ContentOwnerId)

    <!-- Rest of your form controls -->
    <input name="SaveDraft" type="submit" value="SaveDraft" />
    <input name="Publish" type="submit" value="Publish" />
}
 4
Author: Nick Albrecht,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2013-10-17 18:25:50

Moje podejście do JQuery przy użyciu metody rozszerzenia:

public static MvcHtmlString SubmitButtonFor<TController>(this HtmlHelper helper, Expression<Action<TController>> action, string value) where TController : Controller
{
    RouteValueDictionary routingValues = Microsoft.Web.Mvc.Internal.ExpressionHelper.GetRouteValuesFromExpression(action);

    var onclick = string.Format("$('form').first().attr('action', '/{0}')", string.Join("/", routingValues.Values.ToArray().Where(x => x != null).Select(x => x.ToString()).ToArray()));
    var html = "<input type=\"submit\" value=\"" + value + "\" onclick=\"" + onclick + "\" />";

    return MvcHtmlString.Create(html);
}

Możesz go użyć tak:

@(Html.SubmitButtonFor<FooController>(c => c.Save(null), "Save"))

I renderuje tak:

<input type="submit" value="Save" onclick="$('form').first().attr('action', '/Foo/Save')" >
 3
Author: NahuelGQ,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2011-10-19 15:19:54

Dla każdego przycisku submit wystarczy dodać:

$('#btnSelector').click(function () {

    $('form').attr('action', "/Your/Action/);
    $('form').submit();

});
 3
Author: mishap,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2012-07-24 17:23:39

Na podstawie odpowiedzi mkozickiego wymyślam nieco inne rozwiązanie. Nadal używam ActionNameSelectorAttribute, ale musiałem obsługiwać dwa przyciski "Zapisz" i "synchronizuj". Robią prawie to samo, więc nie chciałem mieć dwóch działań.

Atrybut :

public class MultipleButtonActionAttribute : ActionNameSelectorAttribute
{        
    private readonly List<string> AcceptedButtonNames;

    public MultipleButtonActionAttribute(params string[] acceptedButtonNames)
    {
        AcceptedButtonNames = acceptedButtonNames.ToList();
    }

    public override bool IsValidName(ControllerContext controllerContext, string actionName, MethodInfo methodInfo)
    {            
        foreach (var acceptedButtonName in AcceptedButtonNames)
        {
            var button = controllerContext.Controller.ValueProvider.GetValue(acceptedButtonName);
            if (button == null)
            {
                continue;
            }                
            controllerContext.Controller.ControllerContext.RouteData.Values.Add("ButtonName", acceptedButtonName);
            return true;
        }
        return false;
    }
}

Widok

<input type="submit" value="Save" name="Save" />
<input type="submit" value="Save and Sync" name="Sync" />

Controller

 [MultipleButtonAction("Save", "Sync")]
 public ActionResult Sync(OrgSynchronizationEditModel model)
 {
     var btn = this.RouteData.Values["ButtonName"];

Chcę również zaznaczyć, że jeśli działania robią różne rzeczy, prawdopodobnie podążałbym za postem mkozickiego.

 3
Author: Petr J,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2013-09-26 05:35:04

Stworzyłem metodę ActionButton dla HtmlHelper. Wygeneruje on zwykły przycisk wprowadzania z bitem javascript w zdarzeniu onclick , który prześle formularz do określonego kontrolera/akcji.

Używasz helpera w ten sposób

@Html.ActionButton("MyControllerName", "MyActionName", "button text")

Spowoduje to wygenerowanie następującego kodu HTML

<input type="button" value="button text" onclick="this.form.action = '/MyWebsiteFolder/MyControllerName/MyActionName'; this.form.submit();">

Oto kod metody rozszerzenia:

VB.Net

<System.Runtime.CompilerServices.Extension()>
Function ActionButton(pHtml As HtmlHelper, pAction As String, pController As String, pRouteValues As Object, pBtnValue As String, pBtnName As String, pBtnID As String) As MvcHtmlString
    Dim urlHelperForActionLink As UrlHelper
    Dim btnTagBuilder As TagBuilder

    Dim actionLink As String
    Dim onClickEventJavascript As String

    urlHelperForActionLink = New UrlHelper(pHtml.ViewContext.RequestContext)
    If pController <> "" Then
        actionLink = urlHelperForActionLink.Action(pAction, pController, pRouteValues)
    Else
        actionLink = urlHelperForActionLink.Action(pAction, pRouteValues)
    End If
    onClickEventJavascript = "this.form.action = '" & actionLink & "'; this.form.submit();"

    btnTagBuilder = New TagBuilder("input")
    btnTagBuilder.MergeAttribute("type", "button")

    btnTagBuilder.MergeAttribute("onClick", onClickEventJavascript)

    If pBtnValue <> "" Then btnTagBuilder.MergeAttribute("value", pBtnValue)
    If pBtnName <> "" Then btnTagBuilder.MergeAttribute("name", pBtnName)
    If pBtnID <> "" Then btnTagBuilder.MergeAttribute("id", pBtnID)

    Return MvcHtmlString.Create(btnTagBuilder.ToString(TagRenderMode.Normal))
End Function

C # (kod C# jest po prostu dekompilowany z biblioteki DLL VB, dzięki czemu może uzyskać trochę upiększenia... ale czas jest tak krótki : -))

public static MvcHtmlString ActionButton(this HtmlHelper pHtml, string pAction, string pController, object pRouteValues, string pBtnValue, string pBtnName, string pBtnID)
{
    UrlHelper urlHelperForActionLink = new UrlHelper(pHtml.ViewContext.RequestContext);
    bool flag = Operators.CompareString(pController, "", true) != 0;
    string actionLink;
    if (flag)
    {
        actionLink = urlHelperForActionLink.Action(pAction, pController, System.Runtime.CompilerServices.RuntimeHelpers.GetObjectValue(pRouteValues));
    }
    else
    {
        actionLink = urlHelperForActionLink.Action(pAction, System.Runtime.CompilerServices.RuntimeHelpers.GetObjectValue(pRouteValues));
    }
    string onClickEventJavascript = "this.form.action = '" + actionLink + "'; this.form.submit();";
    TagBuilder btnTagBuilder = new TagBuilder("input");
    btnTagBuilder.MergeAttribute("type", "button");
    btnTagBuilder.MergeAttribute("onClick", onClickEventJavascript);
    flag = (Operators.CompareString(pBtnValue, "", true) != 0);
    if (flag)
    {
        btnTagBuilder.MergeAttribute("value", pBtnValue);
    }
    flag = (Operators.CompareString(pBtnName, "", true) != 0);
    if (flag)
    {
        btnTagBuilder.MergeAttribute("name", pBtnName);
    }
    flag = (Operators.CompareString(pBtnID, "", true) != 0);
    if (flag)
    {
        btnTagBuilder.MergeAttribute("id", pBtnID);
    }
    return MvcHtmlString.Create(btnTagBuilder.ToString(TagRenderMode.Normal));
}

Te metody mają różne parametry, ale dla łatwości użycia można stworzyć pewne przeciążenie, które zajmuje tylko parametry, których potrzebujesz.

 1
Author: Max,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2015-10-16 12:42:21