diff --git a/src/System.Web.Mvc/Html/SelectExtensions.cs b/src/System.Web.Mvc/Html/SelectExtensions.cs index af4a6cbff..bc76a4bdd 100644 --- a/src/System.Web.Mvc/Html/SelectExtensions.cs +++ b/src/System.Web.Mvc/Html/SelectExtensions.cs @@ -285,7 +285,7 @@ private static MvcHtmlString ListBoxHelper(HtmlHelper htmlHelper, ModelMetadata private static IEnumerable GetSelectData(this HtmlHelper htmlHelper, string name) { object o = null; - if (htmlHelper.ViewData != null) + if (htmlHelper.ViewData != null && !String.IsNullOrEmpty(name)) { o = htmlHelper.ViewData.Eval(name); } @@ -396,9 +396,9 @@ private static MvcHtmlString SelectInternal(this HtmlHelper htmlHelper, ModelMet // If we haven't already used ViewData to get the entire list of items then we need to // use the ViewData-supplied value before using the parameter-supplied value. - if (defaultValue == null && !String.IsNullOrEmpty(name)) + if (defaultValue == null) { - if (!usedViewData) + if (!usedViewData && !String.IsNullOrEmpty(name)) { defaultValue = htmlHelper.ViewData.Eval(name); } diff --git a/test/System.Web.Mvc.Test/Html/Test/SelectExtensionsTest.cs b/test/System.Web.Mvc.Test/Html/Test/SelectExtensionsTest.cs index f43a3862f..71da0b1a1 100644 --- a/test/System.Web.Mvc.Test/Html/Test/SelectExtensionsTest.cs +++ b/test/System.Web.Mvc.Test/Html/Test/SelectExtensionsTest.cs @@ -19,6 +19,7 @@ public class SelectExtensionsTest : IDisposable { private static readonly ViewDataDictionary _listBoxViewData = new ViewDataDictionary { { "foo", new[] { "Bravo" } } }; private static readonly ViewDataDictionary _dropDownListViewData = new ViewDataDictionary { { "foo", "Bravo" } }; + private static readonly ViewDataDictionary _nestedDropDownListViewData = new ViewDataDictionary { { "foo", "Bravo" } }; private static readonly ViewDataDictionary _nonIEnumerableViewData = new ViewDataDictionary { { "foo", 1 } }; private static readonly ViewDataDictionary _enumDropDownListViewData = new ViewDataDictionary { @@ -1191,6 +1192,48 @@ public void DropDownListForUsesLambdaDefaultValue() + "", html.ToHtmlString()); } + + [Fact] + public void DropDownListForUsesLambdaDefaultValueWhenNested() + { + // Arrange + FooModel model = new FooModel { foo = "Bravo" }; + ViewDataDictionary viewData = new ViewDataDictionary(model); + ViewDataDictionary nestedViewData = MvcHelper.GetNestedViewData(viewData, m => m.foo); + HtmlHelper helper = MvcHelper.GetHtmlHelper(nestedViewData); + SelectList selectList = new SelectList(MultiSelectListTest.GetSampleStrings()); + + // Act + MvcHtmlString html = helper.DropDownListFor(m => m, selectList); + + // Assert + Assert.Equal( + "", + html.ToHtmlString()); + } + + [Fact] + public void DropDownListForUsesLambdaDefaultValueFromViewDataWhenNested() + { + // Arrange + ViewDataDictionary nestedViewData = MvcHelper.GetNestedViewData(_nestedDropDownListViewData, m => m.inner); + HtmlHelper helper = MvcHelper.GetHtmlHelper(nestedViewData); + SelectList selectList = new SelectList(MultiSelectListTest.GetSampleStrings()); + + // Act + MvcHtmlString html = helper.DropDownListFor(m => m.foo, selectList); + + // Assert + Assert.Equal( + "", + html.ToHtmlString()); + } [Fact] public void DropDownListForUsesLambdaDefaultValueWithNullSelectListUsesViewData() @@ -1215,6 +1258,33 @@ public void DropDownListForUsesLambdaDefaultValueWithNullSelectListUsesViewData( html.ToHtmlString()); } + [Fact] + public void DropDownListForUsesLambdaDefaultValueWithNullSelectListUsesViewDataWhenNested() + { + // Arrange + FooContainerModel model = new FooContainerModel { inner = new FooModel { foo = "Bravo" } }; + ViewDataDictionary vdd = new ViewDataDictionary(model) + { + { "foo", new SelectList(MultiSelectListTest.GetSampleStrings()) } + }; + + ViewDataDictionary nestedViewData = MvcHelper.GetNestedViewData(vdd, m => m.inner); + + + HtmlHelper helper = MvcHelper.GetHtmlHelper(nestedViewData); + + // Act + MvcHtmlString html = helper.DropDownListFor(m => m.foo, selectList: null); + + // Assert + Assert.Equal( + "", + html.ToHtmlString()); + } + [Fact] public void DropDownListForWithAttributesDictionary() { @@ -3330,6 +3400,10 @@ private static IEnumerable GetSelectListWithNumericValuesForEnum return selectList; } + private class FooContainerModel + { + public FooModel inner { get; set; } + } private class FooModel { public string foo { get; set; } diff --git a/test/System.Web.Mvc.Test/Util/MvcHelper.cs b/test/System.Web.Mvc.Test/Util/MvcHelper.cs index 992bb481f..8cc869d5c 100644 --- a/test/System.Web.Mvc.Test/Util/MvcHelper.cs +++ b/test/System.Web.Mvc.Test/Util/MvcHelper.cs @@ -4,6 +4,7 @@ using System; using System.Collections; using System.IO; +using System.Linq.Expressions; using System.Web; using System.Web.Mvc; using System.Web.Routing; @@ -152,6 +153,25 @@ public static HttpContextBase GetHttpContext(string appPath, string requestPath, return GetHttpContext(appPath, requestPath, httpMethod, Uri.UriSchemeHttp.ToString(), -1); } + public static ViewDataDictionary GetNestedViewData(ViewDataDictionary viewData, Expression> expression) + { + var metadata = ModelMetadata.FromLambdaExpression(expression, viewData); + var htmlFieldName = ExpressionHelper.GetExpressionText(expression); + + + ViewDataDictionary nestedViewData = new ViewDataDictionary(viewData) + { + Model = metadata.Model, + ModelMetadata = metadata, + TemplateInfo = new TemplateInfo + { + HtmlFieldPrefix = viewData.TemplateInfo.GetFullHtmlFieldName(htmlFieldName), + } + }; + + return new ViewDataDictionary(nestedViewData); + } + public static ViewContext GetViewContextWithPath(string appPath, ViewDataDictionary viewData) { HttpContextBase httpContext = GetHttpContext(appPath, "/request", "GET");