Introduction
Recently, I used the datalist tag in my ASP.NET MVC application and I decided to create an MVC HtmlHelper
extension method to achieve this.
This is what the HTML of a datalist
tag looks like:
<input list="browsers">
<datalist id="browsers">
<option value="Internet Explorer">
<option value="Firefox">
<option value="Chrome">
<option value="Opera">
<option value="Safari">
</datalist>
and with the extension method outlined in this tip, you should be able to generate both tags using the following Razor syntax:
@Html.DataListInputFor(Function(m) m.CountryName, Model.GetCountries)
Using the Code
The HtmlHelper
will generate the input tag and associated datalist
tag. Let's take a look at what the HtmlHelper
looks like:
Option Strict On
Option Explicit On
Imports System.Linq.Expressions
Imports System.Runtime.CompilerServices
Namespace Mvc.HtmlHelpers
Public Module DataListInputExtensions
<Extension>
Public Function DataListInputFor(Of TModel, TProperty)(
htmlHelper As HtmlHelper(Of TModel),
expression As Expression(Of Func(Of TModel, TProperty)),
dataListItems As IEnumerable(Of String)) As IHtmlString
Return htmlHelper.DataListInputFor(expression, dataListItems, Nothing)
End Function
<Extension>
Public Function DataListInputFor(Of TModel, TProperty)(
htmlHelper As HtmlHelper(Of TModel),
expression As Expression(Of Func(Of TModel, TProperty)),
dataListItems As IEnumerable(Of String),
htmlAttributes As Object) As IHtmlString
Dim html As New StringBuilder
Dim input As New TagBuilder("input")
input.MergeAttributes(htmlHelper.AnonymousObjectToHtmlAttributes(htmlAttributes))
Dim metadata = ModelMetadata.FromLambdaExpression(expression, htmlHelper.ViewData)
Dim fullName = htmlHelper.ViewContext.ViewData.TemplateInfo.GetFullHtmlFieldName(
ExpressionHelper.GetExpressionText(expression))
input.GenerateId(fullName)
input.Attributes("name") = fullName
input.Attributes("value") = If(metadata.Model IsNot Nothing,
metadata.Model.ToString,
String.Empty)
Dim dataList As New TagBuilder("datalist")
dataList.GenerateId(String.Format("datalist_{0}", fullName))
input.Attributes("list") = dataList.Attributes("id")
Dim optionsHtml As New StringBuilder
For Each item In dataListItems
Dim opt As New TagBuilder("option")
opt.Attributes("value") = item
optionsHtml.AppendLine(opt.ToString)
Next
dataList.InnerHtml = optionsHtml.ToString
html.AppendLine(input.ToString)
html.AppendLine(dataList.ToString)
Return New HtmlString(html.ToString)
End Function
End Module
End Namespace
The HtmlHelper
can then be used as follows:
@Imports MyProject.Mvc.HtmlHelpers
...
@Html.DataListInputFor(Function(m) m.CountryName, Model.GetCountries)
Where Model.GetCountries()
could look like:
Public ReadOnly Property GetCountries() As IEnumerable(Of String)
Get
Return _db.Countries.Select(Function(c) c.Name)
End Get
End Property