web-dev-qa-db-ja.com

複数の送信ボタンがあるAsp.net mvc3カミソリ

MVC3 Razorを使用しています。ビューには2つの送信ボタンが設定されていますが、問題は、両方の送信ボタンがモデルの検証を引き起こすことです。検証のために、特定の入力コントロールを使用して個々の送信ボタンを接続します。

32
sandeep

私はこれが数ヶ月前であることを知っていますが、ここでの解決策は不必要に複雑であるように見え、受け入れられた答えはまだありません。入力に同じ名前を付け、異なる値を指定する場合、変数として入力の名前を持つ文字列を含めるだけで、コントローラーにその値を取得できます。これが私がこの問題を解決した方法です:

見る:

 <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;
  }
64
Rojzik

ブラウザは、どの送信ボタンを押しても、常にフォーム全体を送信します。

最良の解決策は、name属性の値が同じで、value属性の値が異なる2つの送信ボタンを使用することです。

フォームを送信すると、ボタンの値も送信されます。そのフォーム送信を処理するアクションで、ボタンの値を確認し、それに基づいて正しい検証を実行します。

フォームには次のようなものがあります。

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

Controller\actionは次のようになります。

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

まず、CSSクラス「キャンセル」を追加するだけで、キャンセルボタンでクライアント検証を無効にできます。参照: 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( "Edit")]属性は、MVCに別のメソッド名を使用しているが、それが編集アクション用であることを伝えるために必要であることに注意してください。

そしてあなたの見解では:

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

私の解決策は2つのことをすることでした。 [保存]ボタンと別の[何かを追加]ボタンがあるとします。ユーザーが[保存]をクリックすると、クライアントの検証とサーバーの検証が実行されます。後のボタンでは、検証を行わないでください。

  1. 2番目のボタン(クリック時)のクライアント検証を一時的に無効にします。

<input type = "submit" name = "submit-button" value = "Save" />

<input type = "submit" name = "submit-button" value = "何かを追加" onclick = "document.forms [0] .noValidate = true; document.forms [0] .submit();" />

JavaScriptが無効になっている場合、クライアントの検証は行われません。

  1. サーバー側の注意

フォーム内の送信ボタンをクリックしたときにブライアンが言っているのと同様に、フォーム全体とクリックされた送信ボタンの値が投稿されます。クリックされたボタンは、投稿された名前で区別できます。上記の例では、ユーザーが[保存]ボタンをクリックし、コントローラーのポストアクションで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();
}

Saveメソッドでは、最初にModelState.IsValidであるかどうかを確認し、そうでない場合はAddSomethingメソッドでエラーをクリアします。

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

これは、すべてをきれいに整頓し、テストしやすくすることでした。また、submit-button html name属性の定数を導入できます。 T4MVCでもすべての定数を実行できる可能性があります。 「自動ポストバック」コンボボックスが必要な場合にも同様のソリューションが適用されますが、select要素のonchangeイベントを介して設定される非表示フィールドが必要です。

お役に立てれば。

このコードをテンプレートとして使用するだけです:

@{
    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"/>
2
Chad Brewbaker

最後に、インテリジェント文字列を使用する代わりに、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();
}
1
Reynaldo Zabala

この状況から検証モデルプロパティに[リモート]属性を使用する場合、送信ボタン名はサーバー側に送信されません。

0
Igor Barionov

削除するための個別のアクションが必要な場合は、これを試してください。

コントローラーに削除アクションを追加し、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>

注:ほとんどすべてのブラウザーは、HEAD、PUTなどの他のHTTPメソッドを許可していません、またはDELETE。ただし、HTTPリクエストにヘッダーを追加することで、X-HTTP-Method-Override、これはサービスによって解釈され、実際に使用されるHTTPメソッドに関係なく実行されることになっています。したがって、上記のコードは、リクエストに X-HTTP-Method-Override: DELETE 。 .net frameworkは残りの処理を行い、アクションを削除するよう指示します。

0