W mojej aplikacji ASP.NET MVC renderuję pole wyboru przy użyciu następującego kodu:
<%= Html.CheckBoxFor(i=>i.ReceiveRSVPNotifications) %>
Teraz widzę, że renderuje to zarówno znacznik wejściowy pola wyboru, jak i ukryty znacznik wejściowy. Problem, który mam, polega na tym, że próbuję pobrać wartość z pola wyboru przy użyciu FormCollection:
FormValues["ReceiveRSVPNotifications"]
Otrzymuję wartość „prawda, fałsz”. Patrząc na wyrenderowany kod HTML, widzę:
<input id="ReceiveRSVPNotifications" name="ReceiveRSVPNotifications" value="true" type="checkbox">
<input name="ReceiveRSVPNotifications" value="false" type="hidden">
Wydaje się więc, że kolekcja FormValues łączy te dwie wartości, ponieważ mają one tę samą nazwę.
Jakieś pomysły?
źródło
<input>
tagu.false
. Spójrz na odpowiedź RyanJMcGowana poniżej: „Wysłanie ukrytych danych wejściowych pozwala zorientować się, że pole wyboru było obecne na stronie w momencie przesłania żądania”.Miałem ten sam problem co Shawn (powyżej). To podejście może być świetne w przypadku POST, ale naprawdę jest do bani dla GET. Dlatego zaimplementowałem proste rozszerzenie Html, które po prostu usuwa ukryte pole.
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); }
Problem, który mam teraz, polega na tym, że nie chcę, aby zmiana struktury MVC zepsuła mój kod. Muszę więc upewnić się, że mam pokrycie testowe wyjaśniające tę nową umowę.
źródło
Używam tej alternatywnej metody do renderowania pól wyboru dla formularzy 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); }
Jest podobna do metody Chrisa Kempa , która działa dobrze, z wyjątkiem tego, że ta nie wykorzystuje bazowego
CheckBoxFor
iRegex.Replace
. Opiera się na źródle oryginalnejHtml.CheckBoxFor
metody.źródło
Oto kod źródłowy dodatkowego tagu wejściowego. Microsoft był na tyle uprzejmy, że zamieścił komentarze, które dokładnie dotyczą tego zagadnienia.
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()); }
źródło
Myślę, że najprostszym rozwiązaniem jest wyrenderowanie elementu INPUT bezpośrednio w następujący sposób:
<input type="checkbox" id="<%=Html.IdFor(i => i.ReceiveRSVPNotifications)%>" name="<%=Html.NameFor(i => i.ReceiveRSVPNotifications)%>" value="true" checked="<%=Model.ReceiveRSVPNotifications ? "checked" : String.Empty %>" />
W składni Razor jest to jeszcze prostsze, ponieważ atrybut „zaznaczony” jest bezpośrednio renderowany z wartością „zaznaczoną”, gdy ma wartość „prawdziwą” po stronie serwera.
źródło