Битва Asp.net mvc3 с несколькими кнопками отправки

Я использую MVC3 Razor. У меня есть 2 кнопки отправки кнопок на мой взгляд, но проблема, с которой я сталкиваюсь, заключается в том, что обе кнопки отправки заставляют валидацию модели. Я хочу подключить отдельные кнопки отправки с определенными элементами управления вводом для проверки.

Ответ 1

Я знаю, что это несколько месяцев назад, но решения здесь казались излишне сложными, и пока не принято ответа. Если вы назовете свои входы одинаковыми, но принесите им разные значения, вы можете получить это значение в своем контроллере, просто включив строку с именем ввода в качестве переменной. Вот как я решил эту проблему:

Вид:

 <input type="submit" id="EnterprisePush" name="btnSubmit" value="Push" />
 <input type="submit" id="EnterprisePull" name="btnSubmit" value="Pull" />

Контроллер:

[HttpPost]
public ActionResult EnterpriseAdmin(int id, string btnSubmit, FormCollection collection)
{
  switch (btnSubmit) {
    case "Push":
      /* Do Something here */
      break;
    case "Pull":
      /* Do Something else here */
      break;
  }

Ответ 2

Браузер всегда будет отправлять всю форму независимо от того, какую кнопку отправки вы нажимаете.

Лучшим решением было бы иметь две кнопки отправки с тем же значением для атрибута name и разными значениями атрибутов value.

Когда вы отправляете форму, значение кнопки также будет отправлено. В действии, которое обрабатывает отправку формы, вы проверяете, чтобы увидеть значение кнопки и выполнить правильную проверку на основе этого.

В вашей форме у вас будет что-то вроде этого:

<button type="submit" name="Command" value="command1">Do Command #1</button>
<button type="submit" name="Command" value="command2">Do Command #2</button>

Ваша модель будет выглядеть так:

public class MyFormModel() {
    public string Command {get;set;}
    public string SomeOtherVal {get;set;}
}

Ваш контроллер\действие будет выглядеть следующим образом:

public ActionResult HandleFormSubmit(MyFormModel model) {
    if (model.Command == "command1") {
        // do something
    } else if (model.Command == "command2") {
        // do something else
    }
}

Ответ 3

Во-первых, вы можете отключить проверку клиента на кнопке отмены, просто добавив к нему класс CSS "cancel". См.: Отключить проверку на стороне клиента в MVC 3 "отменить" . отправить кнопку

Во-вторых, также проверяя имя формы элемента отправки, как описано выше, вы можете использовать специальный селектор действий. Здесь мой, который я изначально взял из сообщения в блоге, показанного в комментарии:

/// <summary>
/// Used to vary an action method based on which button in a form was pressed. This
/// is useful but is an anti-pattern because it couples the controller to names
/// used in the form elements. 
/// </summary>
/// <remarks>
/// See the example at http://weblogs.asp.net/dfindley/archive/2009/05/31/asp-net-mvc-multiple-buttons-in-the-same-form.aspx
/// </remarks>
public class AcceptButtonAttribute : ActionMethodSelectorAttribute
{
    public string ButtonName { get; set; }

    public override bool IsValidForRequest(ControllerContext controllerContext, MethodInfo methodInfo)
    {
        var req = controllerContext.RequestContext.HttpContext.Request;
        return !string.IsNullOrEmpty(req.Form[this.ButtonName]);
    }
}

В вашем контроллере:

    [HttpPost]
    [ActionName("Edit")]
    [AcceptButton(ButtonName = "Cancel")]
    public ActionResult Edit_Cancel(MyModel model)
    {
        return RedirectToAction("Index");
    }

    [HttpPost]
    [AcceptButton(ButtonName = "Save")]
    public ActionResult Edit(MyModel model)
    {
        // do real work here
    }

Обратите внимание, что вам нужно атрибут [ActionName ( "Изменить" )], чтобы сообщить MVC, что, хотя и использует другое имя метода, оно предназначено для действия "Редактировать".

И в вашем представлении:

    <input type="submit" name="Save" value="Save" />
    <input type="submit" name="Cancel" value="Cancel" class="cancel" />

Ответ 4

Мое решение состояло в том, чтобы сделать две вещи. Скажем, у нас есть кнопка "Сохранить" и еще одна кнопка "Добавить что-то". Когда пользователь нажимает кнопку "Сохранить" , мы хотим, чтобы проверка клиента и проверка сервера выполнялись. Для более поздней кнопки мы не хотим, чтобы какая-либо проверка имела место.

  • Временно отключить проверку клиента для второй кнопки (по щелчку):

< input type="submit" name= "submit-button" value = "Сохранить" / >

< input type="submit" name= "submit-button" value = "Добавить что-то" onclick = "document.forms [0].noValidate = true; document.forms [0].submit();" / >

Хорошо, что когда JavaScript отключен, проверка клиента никогда не состоялась бы.

  • Позаботьтесь о стороне сервера

Подобно тому, что говорит Брайан, когда вы нажимаете кнопку отправки в форме, публикуется вся форма и значение кнопки отправки нажатой кнопки. Вы можете отличить, какая кнопка нажата по имени. В приведенном выше примере, когда пользователь нажимает кнопку "Сохранить" , и мы читаем Request.Form [ "submit-button" ] в ответном посту контроллера, мы получаем "Сохранить" . Если пользователь нажал кнопку "Добавить что-то", мы получим "Добавить что-то". Именно так должен работать HTML.

Теперь, чтобы обойти вокруг себя магические строки, обычно у меня обычно есть открытый статический класс в контроллере:

public class HomeController
{
    public static class Buttons
    {
        public const string Save = "Save";
        public const string AddSomething = "Add something";
    }
    // Action methods
}

Поэтому вы можете использовать их для формы рендеринга:

&lt;input type="submit" name="submit-button" value="@HomeController.Buttons.Save" /&gt;

И вы можете легко прочитать кнопку, нажатую в контроллере:

[HttpPost]
public ActionResult Index(Model viewModel)
{
    var buttonClicked = Request.Form["submit-button"];
    switch (buttonClicked) {
        case HomeController.Buttons.Save:
            return Save(viewModel);
        case HomeController.Buttons.AddSomething:
            return AddSOmething(viewModel);
    }
    return View();
}

В "Сохранить метод" вы сначала спросите, если ModelState.IsValid и модель представления возврата, если нет, но в методе AddSomething мы устраним любые ошибки:

public ActionResult AddSomething(Model viewModel)
{
    ModelState.Clear();
    // your code to add something to model
    return View(viewModel);
}

Это вы сохранили все чистое, аккуратное и проверяемое. И вы можете ввести константу для атрибута имени html для кнопки отправки. Возможно, также можно будет использовать все константы с T4MVC. Аналогичное решение относится к тому, когда вам нужен комбо-поле "auto postback", за исключением того, что вам нужно скрытое поле, которое устанавливается через событие onchange элемента select.

Надеюсь, что это поможет.

Ответ 5

Просто используйте этот код в качестве шаблона:

@{
    var nextButtonVal = "Next >>";
    var backButtonVal = "<< Back";
    if (IsPost) {
      if(Request["navigate"].Equals(backButtonVal)){Response.Redirect("~/pageFoo");}
      if(Request["navigate"].Equals(nextButtonVal)){Response.Redirect("~/pagebar");}
    }
}

<input type="submit" value="@backButtonVal" title="Back" name="navigate"/>
<input type="submit" value="@nextButtonVal" title="Next" name="navigate"/>

Ответ 6

Последнее, что я хотел бы сделать, это вместо использования интеллектуальных строк использовать enum для определения значения для каждого входного тега. Использование синтаксиса бритвы:

@Enum.GetName(typeof(YourEnumType), yourEnum.WhateverValue)

затем в вашем контроллере:

public ActionResult DoSomethingBasedOnEnumValue(string enumValue)
{
    YourEnumType localVar = (YourEnumType)Enum.Parse(typeof(YourEnumType), enumValue);

    switch(localVar)
    {
        case YourEnumType.Action1:
            //do something
            break;

        case YourEnumType.Action2:
            //do something else
            break;
    }
    return View();
}

Ответ 7

Если вы хотите иметь отдельное действие для удаления, попробуйте это.

добавьте действие удаления в контроллер и отметьте его как HttpDelete,

[HttpDelete]
public ActionResult Edit(int id, string foo) {
   ...
}

И в представлении, имя кнопки должно быть X-HTTP-Method-Override, а значение должно быть DELETE

<button name="X-HTTP-Method-Override" value="DELETE" formnovalidate="formnovalidate" class="cancel">Delete</button>

примечание: все, что большинство браузеров не разрешают другие HTTP-методы, такие как HEAD, PUT или DELETE. но добавив заголовок к HTTP-запросу, X-HTTP-Method-Override, который должен интерпретироваться службой и действовать независимо от используемого метода HTTP. Таким образом, выше код добавит заголовок к запросу, например X-HTTP-Method-Override: DELETE. и .net framework сделает все остальное и направит вас на удаление.

Ответ 8

Введите имя кнопки не на стороне сервера, если во всей этой ситуации вы будете использовать атрибут [Remote] для свойства модели проверки.