MVC, który został naciśnięty przycisk przesyłania

132

Mam dwa przyciski na moim formularzu MVC:

<input name="submit" type="submit" id="submit" value="Save" />
<input name="process" type="submit" id="process" value="Process" />

Na podstawie mojej akcji kontrolera skąd mam wiedzieć, który z nich został naciśnięty?

Coppermill
źródło
Dlaczego nie dodać po prostu zdarzeń onclick do tych przycisków, które przechodzą do ich własnego wywołania AJAX, które będzie prowadziło do odpowiednich metod? czyli <input name="submit" type="submit" id="submit" value="Save" onclick="saveMethod" />:?
ragerory

Odpowiedzi:

173

Nazwij oba przyciski przesyłania tak samo

<input name="submit" type="submit" id="submit" value="Save" />
<input name="submit" type="submit" id="process" value="Process" />

Następnie w kontrolerze uzyskaj wartość zgłoszenia. Tylko kliknięty przycisk przekaże swoją wartość.

public ActionResult Index(string submit)
{
    Response.Write(submit);
    return View();
}

Możesz oczywiście ocenić tę wartość, aby wykonać różne operacje za pomocą bloku przełączników.

public ActionResult Index(string submit)
{
    switch (submit)
    {
        case "Save":
            // Do something
            break;
        case "Process":
            // Do something
            break;
        default:
            throw new Exception();
            break;
    }

    return View();
}
WDuffy
źródło
13
Uważaj na problemy, które lokalizacja może wnieść do tego rozwiązania, na które rozwiązanie Darina nie jest podatne.
Richard Szalay
Dwa dane wejściowe o tej samej nazwie powodują, że tablica jest wysyłana z jednym elementem dla każdej wartości, a nie z pojedynczą wartością, jak to jest sugerowane. Chciałbym więc móc powiedzieć inaczej, ponieważ miałem nadzieję / próbowałem tego użyć, ale to nie działa.
Christopher King
1
@RichardSzalay - nie mógłbyś po prostu użyć <button type="submit" name="action" value="draft"> Internationalized Save Text </button>do celów i18n, więc ciąg znaków dla użytkownika można dostosować, a nazwy elementów formularza nigdy nie są bezpośrednio ujawniane użytkownikowi (co jest dziwne samo w sobie)
KyleMit
48
<input name="submit" type="submit" id="submit" value="Save" />
<input name="process" type="submit" id="process" value="Process" />

A w akcji kontrolera:

public ActionResult SomeAction(string submit)
{
    if (!string.IsNullOrEmpty(submit))
    {
        // Save was pressed
    }
    else
    {
        // Process was pressed
    }
}
Darin Dimitrov
źródło
1
Wyobrażam sobie, że można by dodać więcej przycisków, po prostu dodając go do listy parametrów i nadając mu prawidłowe nazwy. Niezłe rozwiązanie!
GONeale
35

to jest lepsza odpowiedź, więc możemy mieć zarówno tekst, jak i wartość dla przycisku:

http://weblogs.asp.net/dfindley/archive/2009/05/31/asp-net-mvc-multiple-buttons-in-the-same-form.aspx

</p>
<button name="button" value="register">Register</button>
<button name="button" value="cancel">Cancel</button>
</p>

a kontroler:

public ActionResult Register(string button, string userName, string email, string password, string confirmPassword)
{
if (button == "cancel")
    return RedirectToAction("Index", "Home");
...

w skrócie jest to przycisk WYŚLIJ, ale nazwę wybierasz za pomocą atrybutu nazwy, jest to jeszcze potężniejsze, ponieważ nie jesteś zobowiązany do przesłania nazwy lub przycisku w parametrach metody kontrolera, możesz to nazwać jak chcesz ...

Yakir Manor
źródło
Dzięki Sir, właśnie tego potrzebuję
oHoodie
To się psuje, jeśli masz system wielojęzyczny, który zmienia wartość przycisku w zależności od języka.
Dave Tapson,
Dave - Myślę, że nikt nie zakodowałby takiego systemu. To jak zlokalizowanie nazw kontrolerów lub nazw funkcji. Wartość przycisku jest przeznaczony wyłącznie do użytku po stronie serwera - nie ma nigdzie wyświetlane i nie muszą być lokalizowane.
NickG
20

możesz zidentyfikować swój przycisk stamtąd plakietkę jak poniżej, musisz to sprawdzić w swoim kontrolerze

if (Request.Form["submit"] != null)
{
//Write your code here
}
else if (Request.Form["process"] != null)
{
//Write your code here
}
Kinjal Gohil
źródło
jest to bardzo pomocne w sytuacjach, gdy nie chcesz przekazywać nazwy przycisku do wyniku po akcji.
yogihosting
w tym scenariuszu mockowanie klasy Request w teście jednostkowym może być bardziej skomplikowane.
Muflix
6

Oto naprawdę przyjemny i prosty sposób na zrobienie tego z naprawdę łatwymi do wykonania instrukcjami przy użyciu niestandardowego MultiButtonAttribute:

http://blog.maartenballiauw.be/post/2009/11/26/Supporting-multiple-submit-buttons-on-an-ASPNET-MVC-view.aspx

Podsumowując, utwórz przyciski przesyłania w ten sposób:

<input type="submit" value="Cancel" name="action" />
<input type="submit" value="Create" name="action" /> 

Twoje działania w ten sposób:

[HttpPost]
[MultiButton(MatchFormKey="action", MatchFormValue="Cancel")]
public ActionResult Cancel()
{
    return Content("Cancel clicked");
}

[HttpPost]
[MultiButton(MatchFormKey = "action", MatchFormValue = "Create")]
public ActionResult Create(Person person)
{
    return Content("Create clicked");
} 

I stwórz tę klasę:

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

    public override bool IsValidName(ControllerContext controllerContext, string actionName, MethodInfo methodInfo)
    {
        return controllerContext.HttpContext.Request[MatchFormKey] != null &&
            controllerContext.HttpContext.Request[MatchFormKey] == MatchFormValue;
    }
}
piekarnik
źródło
1
Zawsze najlepiej podsumować odnośnik (na dzień, w którym blog znika). Podsumowując, blog opowiada się za posiadaniem MultiButtonAttributeniestandardowego atrybutu, który umożliwia rozróżnianie przycisków przesyłania. Właściwie całkiem niezły pomysł.
Gone Coding,
1
A gdybyś Arnis L.zastosował się do tej samej rady, być może zauważyłeś, że podał dokładnie ten sam link 4 lata wcześniej:>
Gone Coding
3
// Buttons
<input name="submit" type="submit" id="submit" value="Save" />
<input name="process" type="submit" id="process" value="Process" />

// Controller
[HttpPost]
public ActionResult index(FormCollection collection)
{
    string submitType = "unknown";

    if(collection["submit"] != null)
    {
        submitType = "submit";
    }
    else if (collection["process"] != null)
    {
        submitType = "process";
    }

} // End of the index method
Fredrik Stigsson
źródło
Jest to lepsze rozwiązanie niż wszystkie inne publikowane, ponieważ umożliwia spójne przekazywanie bardzo złożonych danych formularzy bez niestandardowych zestawów parametrów w każdej akcji, dzięki czemu logikę kontrolera można w dużym stopniu dostosować do złożonych formularzy. Kudos Fredrik :) Zakładam, że ta kolekcja FormCollection przejdzie w wielu formach?
Stokely
Dziękuję Stokely. Możesz wywołać tę metodę z wielu formularzy, jeśli wykonasz wywołanie ajax, możesz dołączyć wiele formularzy do tej samej kolekcji FormCollection.
Fredrik Stigsson
3

Aby to ułatwić, powiem, że możesz zmienić przyciski na następujące:

<input name="btnSubmit" type="submit" value="Save" />
<input name="btnProcess" type="submit" value="Process" />

Twój kontroler:

public ActionResult Create(string btnSubmit, string btnProcess)
{
    if(btnSubmit != null)
       // do something for the Button btnSubmit
    else 
       // do something for the Button btnProcess
}
Zonke-Bonke S'cekeleshe Msibi
źródło
2

Ten post nie będzie odpowiadał Coppermillowi, ponieważ otrzymał odpowiedź dawno temu. Mój post będzie pomocny dla tego, kto będzie szukał takiego rozwiązania. Przede wszystkim muszę powiedzieć, że "rozwiązanie WDuffy jest całkowicie poprawne" i działa dobrze, ale moje rozwiązanie (nie moje) zostanie użyte w innych elementach i uniezależni warstwę prezentacji od kontrolera (ponieważ twój kontroler zależy od „wartość”, która służy do wyświetlania etykiety przycisku, ta funkcja jest ważna dla innych języków).

Oto moje rozwiązanie, nadaj im różne nazwy:

<input type="submit" name="buttonSave" value="Save"/>
<input type="submit" name="buttonProcess" value="Process"/>
<input type="submit" name="buttonCancel" value="Cancel"/>

I musisz określić nazwy przycisków jako argumenty w akcji jak poniżej:

public ActionResult Register(string buttonSave, string buttonProcess, string buttonCancel)
{
    if (buttonSave!= null)
    {
        //save is pressed
    }
    if (buttonProcess!= null)
    {
        //Process is pressed
    }
    if (buttonCancel!= null)
    {
        //Cancel is pressed
    }
}

gdy użytkownik prześle stronę za pomocą jednego z przycisków, tylko jeden z argumentów będzie miał wartość. Myślę, że będzie to pomocne dla innych.

Aktualizacja

Ta odpowiedź jest dość stara i właściwie ponownie rozważam swoją opinię. być może powyższe rozwiązanie jest dobre dla sytuacji, która przekazuje parametr do właściwości modelu. nie przejmuj się i wybierz najlepsze rozwiązanie dla swojego projektu.

Ali Fattahian
źródło
Pewna konstruktywna krytyka: jest to dobrze uwzględnione w istniejących odpowiedziach w chwili, gdy to opublikowałeś. Ponadto nie jest to dobrze skalowane. HTML odeśle tylko input[type=submit]wartość, która została wyzwolona, ​​więc wszystkie mogą powiązać model z właściwością o tej samej name(np. action), A następnie możesz rozróżnić przyciski na podstawie valuetego ciągu bez konieczności wprowadzania tak wielu zmiennych w podpisie . Poświęć trochę czasu na przemyślenie formatowania / wcięć przed wysłaniem.
KyleMit
0

Nie możesz się tego dowiedzieć za pomocą Request.Form Collection? Po kliknięciu procesu request.form ["proces"] nie będzie pusty

chugh97
źródło
0

Nadaj nazwę obu przyciskom i pobierz wartość sprawdzenia z formularza.

<div>
   <input name="submitButton" type="submit" value="Register" />
</div>

<div>
   <input name="cancelButton" type="submit" value="Cancel" />
</div>

Po stronie sterownika:

public ActionResult Save(FormCollection form)
{
 if (this.httpContext.Request.Form["cancelButton"] !=null)
 {
   // return to the action;
 }

else if(this.httpContext.Request.Form["submitButton"] !=null)
 {
   // save the oprtation and retrun to the action;
 }
}
Aniket Sharma
źródło
0

Na stronach Core 2.2 Razor działa ta składnia:

    <button type="submit" name="Submit">Save</button>
    <button type="submit" name="Cancel">Cancel</button>
public async Task<IActionResult> OnPostAsync()
{
    if (!ModelState.IsValid)
        return Page();
    var sub = Request.Form["Submit"];
    var can = Request.Form["Cancel"];
    if (sub.Count > 0)
       {
       .......
Leftware
źródło
To może zadziałać, ale ja wolę parametry string submitniż pisanie string submit = Request.Form["Submit"];. Jedną z największych zalet Razor Pages i / lub MVC jest czytelność metod, w przeciwnym razie może to być PHP.
yzorg