CheckBoxFor एक अतिरिक्त इनपुट टैग क्यों प्रस्तुत करता है, और मैं FormCollection का उपयोग करके मूल्य कैसे प्राप्त कर सकता हूं?


130

मेरे ASP.NET MVC ऐप में, मैं निम्नलिखित कोड का उपयोग करके एक चेकबॉक्स प्रदान कर रहा हूं:

<%= Html.CheckBoxFor(i=>i.ReceiveRSVPNotifications) %>

अब, मैं देखता हूं कि यह चेकबॉक्स इनपुट टैग और एक छिपे हुए इनपुट टैग दोनों को प्रस्तुत करता है। समस्या यह है कि मैं कर रहा हूँ जब मैं कोशिश कर रहा हूँ FormCollection का उपयोग कर चेकबॉक्स से मान प्राप्त करें:

FormValues["ReceiveRSVPNotifications"]

मुझे मूल्य "सच्चा, झूठा" मिलता है। प्रस्तुत HTML को देखते समय, मैं निम्नलिखित देख सकता हूं:

 <input id="ReceiveRSVPNotifications" name="ReceiveRSVPNotifications" value="true" type="checkbox">
 <input name="ReceiveRSVPNotifications" value="false" type="hidden">

इसलिए FormValues ​​संग्रह इन दो मूल्यों में शामिल होता है क्योंकि उनके पास एक ही नाम है।

कोई विचार?

जवाबों:


168

यहाँ एक नज़र है:

http://forums.asp.net/t/1314753.aspx

यह एक बग नहीं है, और वास्तव में वही दृष्टिकोण है जो रूबी ऑन रेल्स और मोनोरेल दोनों का उपयोग करता है।

जब आप एक चेकबॉक्स के साथ एक फॉर्म जमा करते हैं, तो चेकबॉक्स चेक किए जाने पर ही मूल्य पोस्ट किया जाता है। इसलिए, यदि आप चेकबॉक्स को अनियंत्रित छोड़ देते हैं, तो सर्वर को कुछ भी नहीं भेजा जाएगा जब कई स्थितियों में आप इसके बजाय गलत भेजना चाहेंगे। जैसा कि छिपे हुए इनपुट में चेकबॉक्स के समान नाम है, तो यदि चेकबॉक्स अनियंत्रित है, तो भी आपको सर्वर पर भेजा गया एक 'गलत' मिलेगा।

जब चेकबॉक्स की जाँच की जाती है, तो ModelBinder स्वचालित रूप से 'सही' को 'सही, गलत' से निकालने का ध्यान रखेगा।


10
यह एक अच्छी व्याख्या है लेकिन कुछ मामलों में आप क्वेरी स्ट्रिंग में 'कुछ नहीं' प्राप्त करना चाहते हैं जब ckecbox की जाँच नहीं की जाती है - इसलिए डिफ़ॉल्ट व्यवहार। क्या यह एचटीएमएल हेल्पर का उपयोग करना संभव है या क्या मुझे केवल <input>टैग का उपयोग करना है ।
मैक्सीमिलियन मेजर

13
मुझे यह पसंद नहीं है .... मेरे पास एक ऐसा खोज पृष्ठ है जो GET का उपयोग करता है और अब मेरा url सच / झूठे params से भरा है ...
Shawn Mclean

1
वाह, यह अप्रत्याशित है। क्या इसका मतलब यह है कि HTML चेकबॉक्स वास्तव में "टूटा हुआ" है?
इस्तिनिपोव

1
@Isantipov: नहीं, इसका मतलब यह है कि ये वेब फ्रेमवर्क इंगित करने के लिए चेकबॉक्स के लिए पोस्ट किए गए मूल्य की अनुपस्थिति पर भरोसा नहीं करते हैं false। नीचे RyanJMcGowan के उत्तर को देखें: "एक छिपे हुए इनपुट को भेजने से यह जानना संभव हो जाता है कि चेकबॉक्स पृष्ठ पर मौजूद था जब अनुरोध प्रस्तुत किया गया था।"
रॉबर्ट हार्वे

1
खैर @Robert, यह मेरे लिए काम नहीं करता है। अगर मेरे chbox MyCheckbox की जाँच नहीं की जाती है, तो मैं गलत हो जाता हूँ, जब MyCheckbox की जाँच की जाती है, तब मुझे इसके मूल्य के रूप में [true, false] का एक सरणी मिलता है। मैं पूरे फॉर्म को क्रमबद्ध कर रहा हूं और इसे अजाक्स के माध्यम से कंट्रोलर एक्शन के पास भेज देता हूं। AddToOrder (MyModel मॉडल) जहां मुझे मॉडल मिलता है। मेरा चेकबॉक्स = सही के बजाय गलत
nickornotto

18

मुझे शॉन (ऊपर) जैसी ही समस्या थी। यह दृष्टिकोण POST के लिए बहुत अच्छा हो सकता है, लेकिन यह वास्तव में GET के लिए बेकार है। इसलिए मैंने एक साधारण एचटीएमएल एक्सटेंशन लागू किया जो कि छिपे हुए क्षेत्र को बाहर निकालता है।

public static MvcHtmlString BasicCheckBoxFor<T>(this HtmlHelper<T> html, 
                                                Expression<Func<T, bool>> expression,
                                                object htmlAttributes = null)
{
    var result = html.CheckBoxFor(expression).ToString();
    const string pattern = @"<input name=""[^""]+"" type=""hidden"" value=""false"" />";
    var single = Regex.Replace(result, pattern, "");
    return MvcHtmlString.Create(single);
}

मेरे पास अब जो समस्या है वह यह है कि मैं अपने कोड को तोड़ने के लिए MVC फ्रेमवर्क में बदलाव नहीं चाहता। इसलिए मुझे यह सुनिश्चित करना होगा कि मेरे पास इस नए अनुबंध की व्याख्या करने वाला टेस्ट कवरेज है।


5
क्या आप थोड़ा गंदा महसूस नहीं करते हैं कि आपने केवल एक चेकबॉक्स इनपुट बनाने के बजाय छिपे हुए इनपुट को मिलान / हटाने के लिए regex का उपयोग किया है ? :)
टिम होब्स

2
नहीं, मैंने ऐसा इसलिए किया कि मैं मौजूदा व्यवहार में संशोधन कर रहा था, बजाय इसके कि मैं खुद को फिर से लागू करूं। इस तरह से मेरा बदलाव किसी भी परिवर्तन के साथ तालमेल बिठाएगा, जो एमएस ने लुढ़का दिया।
क्रिस केम्प

10
बस एक छोटा सा अवलोकन। आपका कार्यान्वयन किसी भी कस्टम विशेषता को प्रस्तुत नहीं करेगा जो पारित हो। पैरामीटर "htmlAttributes" मूल "CheckBoxFor" विधि पर पारित नहीं किया गया है।
एमिल लुंडिन

16

मैं GET फॉर्म के चेकबॉक्स को रेंडर करने के लिए इस वैकल्पिक विधि का उपयोग करता हूं:

/// <summary>
/// Renders checkbox as one input (normal Html.CheckBoxFor renders two inputs: checkbox and hidden)
/// </summary>
public static MvcHtmlString BasicCheckBoxFor<T>(this HtmlHelper<T> html, Expression<Func<T, bool>> expression, object htmlAttributes = null)
{
    var tag = new TagBuilder("input");

    tag.Attributes["type"] = "checkbox";
    tag.Attributes["id"] = html.IdFor(expression).ToString();
    tag.Attributes["name"] = html.NameFor(expression).ToString();
    tag.Attributes["value"] = "true";

    // set the "checked" attribute if true
    ModelMetadata metadata = ModelMetadata.FromLambdaExpression(expression, html.ViewData);
    if (metadata.Model != null)
    {
        bool modelChecked;
        if (Boolean.TryParse(metadata.Model.ToString(), out modelChecked))
        {
            if (modelChecked)
            {
                tag.Attributes["checked"] = "checked";
            }
        }
    }

    // merge custom attributes
    tag.MergeAttributes(HtmlHelper.AnonymousObjectToHtmlAttributes(htmlAttributes));

    var tagString = tag.ToString(TagRenderMode.SelfClosing);
    return MvcHtmlString.Create(tagString);
}

यह क्रिस केम्प की विधि के समान है , जो ठीक काम कर रहा है, इसके अलावा यह अंतर्निहित और उपयोग नहीं करता है । यह मूल विधि के स्रोत पर आधारित है ।CheckBoxForRegex.ReplaceHtml.CheckBoxFor


यह इस समस्या का सबसे अच्छा समाधान है और एमवीसी ढांचे का हिस्सा होना चाहिए ... यह पूरी तरह से काम करता है। मुझे यकीन नहीं है कि आपके उत्तर को अधिक ध्यान क्यों नहीं मिला ... धन्यवाद!
user2315985

@ user2315985: मैंने इसे थोड़ी देर से पोस्ट किया;) यही कारण है।
टॉम पॉज़्रुक

आप संग्रह गुणों को कैसे संभाल रहे हैं? डिफ़ॉल्ट मॉडल बाइंडर जब बाइंडिंग इंडेक्स में गैप का सामना करता है, तो यह बाइंडिंग वैल्यू को रोक देगा, इसलिए ऐसा लगता है कि यह आपके एक्सटेंशन का उपयोग कर रहा है, यदि, कहते हैं, पहले और आखिरी मान की जाँच की गई थी, तो आपको दूसरे मूल्य के बारे में कभी पता नहीं चलेगा जिसे आपको प्राप्त करना चाहिए। । या क्या मैं कुछ न कुछ भूल रहा हूं?
टायसन टी।

@TiesonT। जब तक आप अपने खुद के मॉडल बाइंडर को लिखना नहीं चाहते हैं, तब तक एकमात्र उपाय अंतराल को रोकना है। यह विधि अनियंत्रित चेकबॉक्स के लिए गलत नहीं भेजती है, इसलिए आप मूल Html.CheckBoxFor विधि का उपयोग करना चाहते हैं जो ऐसा करती है।
टॉम पॉज़्रुक

10

यहां अतिरिक्त इनपुट टैग के लिए स्रोत कोड है । Microsoft उन टिप्पणियों को शामिल करने के लिए पर्याप्त था जो इसे सटीक रूप से संबोधित करते हैं।

if (inputType == InputType.CheckBox)
{
    // Render an additional <input type="hidden".../> for checkboxes. This
    // addresses scenarios where unchecked checkboxes are not sent in the request.
    // Sending a hidden input makes it possible to know that the checkbox was present
    // on the page when the request was submitted.
    StringBuilder inputItemBuilder = new StringBuilder();
    inputItemBuilder.Append(tagBuilder.ToString(TagRenderMode.SelfClosing));

    TagBuilder hiddenInput = new TagBuilder("input");
    hiddenInput.MergeAttribute("type", HtmlHelper.GetInputTypeString(InputType.Hidden));
    hiddenInput.MergeAttribute("name", fullName);
    hiddenInput.MergeAttribute("value", "false");
    inputItemBuilder.Append(hiddenInput.ToString(TagRenderMode.SelfClosing));
    return MvcHtmlString.Create(inputItemBuilder.ToString());
}

9

मुझे लगता है कि सरलतम उपाय INPUT तत्व को सीधे इस प्रकार प्रस्तुत करना है:

<input type="checkbox" 
       id="<%=Html.IdFor(i => i.ReceiveRSVPNotifications)%>"
       name="<%=Html.NameFor(i => i.ReceiveRSVPNotifications)%>"
       value="true"
       checked="<%=Model.ReceiveRSVPNotifications ? "checked" : String.Empty %>" />

रेजर सिंटैक्स में यह और भी आसान है, क्योंकि 'चेक' विशेषता सीधे 'चेक' वैल्यू के साथ प्रदान की जाती है, जब 'ट्रू' सर्वर-साइड वैल्यू दी जाती है।

हमारी साइट का प्रयोग करके, आप स्वीकार करते हैं कि आपने हमारी Cookie Policy और निजता नीति को पढ़ और समझा लिया है।
Licensed under cc by-sa 3.0 with attribution required.