2012-03-01 10 views
3

私のASP.NET MVC Razorページにフォームが必要です。私の好みは、次の構文を使用することです:Html.BeginForm()へのHTML属性の追加のバリエーション

@using (Html.BeginForm()) 
{ 
} 

しかし、私はいくつかの属性は、フォームに追加する必要があります。だから私は次のようなものになった:

@using (Html.BeginForm(null, null, FormMethod.Post, new { name = "value" })) 
{ 
} 

しかし、これは望ましくない副作用があります。このページのリクエストにクエリ引数がある場合、最初のフォームはフォームが送信されるときにそれらを渡します。ただし、2番目のバージョンではありません。

なぜBeginForm()が属性をサポートしていないのか分かりませんが、BeginForm()に属性を追加する簡単な方法はありますが、forが送信されたときに引き続きクエリ引数を渡しますか?

EDIT:この構文を使用するとき

<form action="@Request.RawUrl" method="post" name="value"> 
</form> 

がしかし、クライアント側の検証が無効になっている:

このに見た後、最善の解決策は、このようなものであると思われます。より複雑で潜在的に信頼性のない構築物がなければ、この状況に対する良い解決策はないようです。

答えて

4

確かに事実だが、私は、クライアント側の検証のために使用される内部のフォームのコンテキストを維持するために、カスタムのヘルパーとなるだろう:

public static class FormExtensions 
{ 
    private static object _lastFormNumKey = new object(); 

    public static IDisposable BeginForm(this HtmlHelper htmlHelper, object htmlAttributes) 
    { 
     string rawUrl = htmlHelper.ViewContext.HttpContext.Request.RawUrl; 
     return htmlHelper.FormHelper(rawUrl, FormMethod.Post, HtmlHelper.AnonymousObjectToHtmlAttributes(htmlAttributes)); 
    } 

    private static int IncrementFormCount(IDictionary items) 
    { 
     object obj2 = items[_lastFormNumKey]; 
     int num = (obj2 != null) ? (((int)obj2) + 1) : 0; 
     items[_lastFormNumKey] = num; 
     return num; 
    } 

    private static string DefaultFormIdGenerator(this HtmlHelper htmlhelper) 
    { 
     int num = IncrementFormCount(htmlhelper.ViewContext.HttpContext.Items); 
     return string.Format(CultureInfo.InvariantCulture, "form{0}", new object[] { num }); 
    } 

    private static IDisposable FormHelper(this HtmlHelper htmlHelper, string formAction, FormMethod method, IDictionary<string, object> htmlAttributes) 
    { 
     var builder = new TagBuilder("form"); 
     builder.MergeAttributes<string, object>(htmlAttributes); 
     builder.MergeAttribute("action", formAction); 
     builder.MergeAttribute("method", HtmlHelper.GetFormMethodString(method), true); 
     bool flag = htmlHelper.ViewContext.ClientValidationEnabled && !htmlHelper.ViewContext.UnobtrusiveJavaScriptEnabled; 
     if (flag) 
     { 
      builder.GenerateId(htmlHelper.DefaultFormIdGenerator()); 
     } 
     htmlHelper.ViewContext.Writer.Write(builder.ToString(TagRenderMode.StartTag)); 
     var form = new MvcForm(htmlHelper.ViewContext); 
     if (flag) 
     { 
      htmlHelper.ViewContext.FormContext.FormId = builder.Attributes["id"]; 
     } 
     return form; 
    } 
} 

このように使用することができた:

@using (Html.BeginForm(htmlAttributes: new { name = "value" })) 
{ 
    ... 
} 
+0

おかげ@Darinを。 'IncrementFormCount'、' DefaultFormIdGenerator'、そして 'FormHelper'が何をするのか少し説明できますか? –

+0

@ JonathanWood、FormHelperはTagBuildersを使って '

'要素を生成します。 'DefaultFormIdGenerator'は、基本的に、HttpContextにその数を格納し、毎回インクリメントすることによって、与えられたビューにレンダリングされるフォームの数を追跡します。基本的には、form0、form1、form2などのフォームIDを持つことができます。これは、控えめなクライアント側の検証によって使用されます。 –

+0

ありがとうございました。それはうまくいくようです。しかし、受け入れる 'BeginForm()'のバージョンとあいまいさを避けるために、 '@using(Html.BeginForm(HtmlHelper.AnonymousObjectToHtmlAttributes(new {@class =" form-horizo​​ntal "})))ちょうどルート値。 –

1

私は同様の問題を抱えていましたが、ここでは簡単な解決策があります(MVC4で動作します)。

拡張メソッド宣言:

public static MvcForm BeginForm(this HtmlHelper helper, object htmlAttributes) 
{ 
     return helper.BeginForm(helper.ViewContext.RouteData.Values["Action"].ToString(), 
           helper.ViewContext.RouteData.Values["Controller"].ToString(), 
           FormMethod.Post, htmlAttributes); 
} 

し、あなたのページでそれを使用します。

@using (Html.BeginForm(htmlAttributes: new {@class="form-horizontal"})) 
{ 
... 
} 
+2

このメソッドを使用してすべてのクエリ文字列を失います。 –

0

ソースコードに小さな変更:

http://aspnetwebstack.codeplex.com/SourceControl/latest#src/System.Web.Mvc/Html/FormExtensions.cs

public static MvcForm BeginForm(this HtmlHelper htmlHelper, object htmlAttributes) 
{ 
    // generates <form action="{current url}" method="post">...</form> 
    string formAction = htmlHelper.ViewContext.HttpContext.Request.RawUrl; 
    return FormHelper(htmlHelper, formAction, FormMethod.Post, new RouteValueDictionary(htmlAttributes)); 
} 

private static MvcForm FormHelper(this HtmlHelper htmlHelper, string formAction, FormMethod method, IDictionary<string, object> htmlAttributes) 
{ 
    TagBuilder tagBuilder = new TagBuilder("form"); 
    tagBuilder.MergeAttributes(htmlAttributes); 
    // action is implicitly generated, so htmlAttributes take precedence. 
    tagBuilder.MergeAttribute("action", formAction); 
    // method is an explicit parameter, so it takes precedence over the htmlAttributes. 
    tagBuilder.MergeAttribute("method", HtmlHelper.GetFormMethodString(method), true); 

    bool traditionalJavascriptEnabled = htmlHelper.ViewContext.ClientValidationEnabled 
             && !htmlHelper.ViewContext.UnobtrusiveJavaScriptEnabled; 

    if (traditionalJavascriptEnabled) 
    { 
     // forms must have an ID for client validation 
     tagBuilder.GenerateId(htmlHelper.ViewContext.FormIdGenerator()); 
    } 

    htmlHelper.ViewContext.Writer.Write(tagBuilder.ToString(TagRenderMode.StartTag)); 
    MvcForm theForm = new MvcForm(htmlHelper.ViewContext); 

    if (traditionalJavascriptEnabled) 
    { 
     htmlHelper.ViewContext.FormContext.FormId = tagBuilder.Attributes["id"]; 
    } 

    return theForm; 
} 
+0

'ViewContext.FormIdGenerator()'は内部的です。 :-( –

関連する問題