Reputation: 1250
When filtering a data list in MVC(4) I am binding several filter inputs to a dictionary that lives in the ViewModel model.
I've been able to do that with a literal declaration of the input like this (.aspx engine):
<input type="text" name='Model.Filters[matchId].Filter'
value='<%: Model.Filters["matchId"].Filter %>' />
Where "matchId" is the name of the column being filtered. The Model.Filter dictionary is defined as
IDictionary<string,FilterObject>
with FilterObject for the moment being simply:
[Serializable]
public class FilterObject
{
public FilterObject()
{
Filter = "";
}
public FilterObject(String value)
{
Filter = value;
}
//[DefaultValue("")]
public String Filter { get; set; }
}
So - that works as long as the Model.Filters Dictionary is initialized with all of the keys for which there Filter inputs, otherwise we naturally get a "key not found" runtime exception.
Hard-coding column-name strings into the controller is ugly and it feels like it should be possible to avoid the exception using an @Html.TextBoxFor<>(....) but I cannot find a syntax that works (or doesn't just break on invalid index object type etc.) for example:
Html.TextBoxFor(m=>m.Filters.FirstOrDefault(k=>k.Key=="matchId").Value.Filter)
Produces HTML of
<input id="Value_Filter" name="Value.Filter" type="text" value="" />
which clearly does nothing useful
I'm pretty sure I'm just missing something but all the Dictionary binding examples I have found depend on Loops and binding to an int index, and I am at this point stumped, short of writing a custom Helper which seems overkill.
Any help greatly appreciated :-)
Upvotes: 0
Views: 1236
Reputation: 1250
Ha! I stopped fighting the tide and wrote a Helper for this, easier than I thought:
public static MvcHtmlString TextBoxForFilterDictionary(this HtmlHelper helper, IDictionary<string, FilterObject> filters, string fieldName, object htmlAttributes = null)
{
FilterObject filter;
if (!filters.TryGetValue(fieldName, out filter))
{
filter = new FilterObject();
}
string nameAttribute = String.Format("Model.Filters[{0}].Filter", fieldName);
MvcHtmlString html = helper.TextBox(nameAttribute, filter.Filter, htmlAttributes);
return html;
}
And in the HTML:
<%: Html.TextBoxForFilterDictionary(Model.Filters, "matchId")%>
<!-- a bunch of other formatting HTML -->
<%: Html.TextBoxForFilterDictionary(Model.Filters, "matchName")%>
<!-- and so on -->
My generic ViewModel now carries everything the list needs for sorting, paging, and filtering, no filter Dictionary initialization required and nary a weakly typed object in sight.
Worth the little extra effort!
Upvotes: 1