English | 简体中文 | 繁體中文 | Русский язык | Français | Español | Português | Deutsch | 日本語 | 한국어 | Italiano | بالعربية

ASP.NET MVCで複数のボタンを提交する方法

時々このような状況に直面します:フォーム上に複数のボタンが必要で、それぞれ異なる機能を持っています。例えば、シンプルな承認機能などです。

 

WebFormを使用する場合、これについて議論する必要はありませんが、ASP.NET MVCではフォームは1つのActionハンドラにのみ提交できますが、少し厄介です。 

方法1:クライアントサイドスクリプトの使用 

例えば、Viewでこんな感じで書きます:

<input type="submit" value="承認通过" onclick='this.form.action="<%=Url.Action("Action1)%>"/>}}
<input type="submit" value="承認不通过" onclick='this.form.action="<%=Url.Action("Action2)%>" />}}
<input type="submit" value="戻る" onclick='this.form.action="<%=Url.Action("Action3)%>" />}}

提交ボタンをクリックした際に、まずFormのaction属性を変更し、フォームをボタンに関連付けられたactionハンドラに送信します。 

しかし、時にはAction1および2のロジックは非常に似ており、たぶんあるフィールドの値を変更しているだけかもしれません1または0であれば、2つのactionに分けていくのは少し余計に感じられます。 

方法2:Actionでどのボタンで送信されたかを判断します 

Viewでは、クライアントサイドのスクリプトを使用せず、各ボタンのname属性を適切に設定します: 

<input type="submit" value="承認通过" name="action" />}}
<input type="submit" value="承認不通过" name="action"/>}}
<input type="submit" value="戻る" name="action"/>}}

それでは、コントローラーで判断します:

[HttpPost]
 public ActionResult Index(string action /* 他のパラメータ*/)
 {
  if (action=="承認通过")
  {
   //
  }
  else if (action=="承認不通过")
  {
//
  }
  else
  {
   //
  }
 }

数年前にaspのコードを書いていたときはよくこんな方法を使っていました… 

Viewはシンプルになったが、Controllerは複雑化しました。

 Viewに過度に依存すると、問題が発生する可能性があります。もし、ある日、顧客が「ボタンのテキストを「承認済み」と変更する」または「多言語版を作成する」と言ったら、面倒なことになります。 

 方法3:ActionSelectorの使用 

ActionSelectorの基本原理について詳しく見てみるには、このPOSTを使用してActionSelectorでActionの選択を制御する方法が参考になります。 

このメソッドを使用すると、以下のようにコントローラを書くことができます:

[HttpPost]
[MultiButton("action1)
public ActionResult Action1(),
{
 //
 return View();
}
[HttpPost]
[MultiButton("action2)
public ActionResult Action2(),
{
 //
 return View();
}

Viewの中で: 

<input type="submit" value="承認可" name="action1" />}}
<input type="submit" value="承認不可" name="action2"/>}}
<input type="submit" value="戻る" name="action3"/>}}

この時点で、ControllerはボタンのValue値に依存する必要はありません。 

MultiButtonAttributeの定義は以下の通りです:

public class MultiButtonAttribute : ActionNameSelectorAttribute
{
 public string Name { get; set; }
 public MultiButtonAttribute(string name)
 {
  this.Name = name;
 }
 public override bool IsValidName(ControllerContext controllerContext,
  string actionName, System.Reflection.MethodInfo methodInfo)
 {
  if (string.IsNullOrEmpty(this.Name))
  {
   return false;
  }
  return controllerContext.HttpContext.Request.Form.AllKeys.Contains(this.Name);
 }
}

方法四:改善

Controller: 

[HttpPost] 
[MultiButton(Name = "delete", Argument = "id")] 
public ActionResult Delete(string id) 
{ 
var response = System.Web.HttpContext.Current.Response; 
response.Write("Delete action was invoked with " + id); 
return View(); 
} 

View:

<input type="submit" value="not important" name="delete" />}}
<input type="submit" value="not important" name="delete:id" />}}

MultiButtonAttribute定義: 

コード

[AttributeUsage(AttributeTargets.Method, AllowMultiple = false, Inherited = true)] 
public class MultiButtonAttribute : ActionNameSelectorAttribute 
{ 
public string Name { get; set; } 
public string Argument { get; set; } 
public override bool IsValidName(ControllerContext controllerContext, string 
actionName, MethodInfo methodInfo) 
{ 
var key = ButtonKeyFrom(controllerContext); 
var keyIsValid = IsValid(key); 
if (keyIsValid) 
{ 
UpdateValueProviderIn(controllerContext, ValueFrom(key)); 
} 
return keyIsValid; 
} 
private string ButtonKeyFrom(ControllerContext controllerContext) 
{ 
var keys = controllerContext.HttpContext.Request.Params.AllKeys; 
return keys.FirstOrDefault(KeyStartsWithButtonName); 
} 
private static bool IsValid(string key) 
{ 
return key != null; 
} 
private static string ValueFrom(string key) 
{ 
var parts = key.Split(":".ToCharArray()); 
return parts.Length < 2 ? null : parts[1]; 
} 
private void UpdateValueProviderIn(ControllerContext controllerContext, 
string value) 
{ 
if (string.IsNullOrEmpty(Argument)) return; 
controllerContext.Controller.ValueProvider[Argument] = new ValueProviderResult
 (value, value, null); 
} 
private bool KeyStartsWithButtonName(string key) 
{ 
return key.StartsWith(Name, StringComparison.InvariantCultureIgnoreCase); 
} 
} 
//MVCの場合 2.0の話、UpdateValueProviderInメソッドを変更します:
private void UpdateValueProviderIn(ControllerContext controllerContext, string value)
{
 if (string.IsNullOrEmpty(Argument))
 return;
 controllerContext.RouteData.Values[this.Argument] = value;
} 

これで本文のすべての内容が終わりました。皆様の学習に役立つことを願っています。また、呐喊教程を多くのサポートをお願いします。

声明:本文の内容はインターネットから取得しており、著作権者に帰属します。インターネットユーザーが自発的に貢献し、自己でアップロードしたものであり、本サイトは所有権を有しておらず、人工的な編集処理も行われていません。著作権侵害を疑う内容がある場合は、以下のメールアドレスまでご連絡ください:notice#oldtoolbag.com(メールを送信する際には、#を@に変更してください。報告を行い、関連する証拠を提供してください。一旦確認がついたら、本サイトは即座に侵害を疑われる内容を削除します。)

おすすめ