Tra le varie novità di HTML5, una che risulta estremamente utile è l'elemento DataList, che implementa un comportamento simile a quello di una ComboBox: questo tag va utilizzato in concomitanza con un input testuale ed è in grado di fornire una serie di suggerimenti o di valori predefiniti, che poi possono essere comunque modificati dall'utente. Possiamo vederne un esempio in figura.

Il markup necessario per realizzare un effetto del genere consiste nell'abbinare, tramite l'attributo list, un input[type=text] alla corrispondente DataList:
<input type="text" ... list="nome_dataList" />; <datalist id="nome_dataList"> <option value="option1">option1</option> <option value="option2">option2</option> <option value="option3">option3</option> </datalist>
ASP.NET MVC non presenta un html helper nativo per realizzare un tag di questo tipo, ma possiamo costruirne uno in maniera abbastanza semplice. Tutto ciò che dobbiamo fare, infatti, è creare un extension method con la signature seguente:
public static MvcHtmlString DataListFor<TModel, TProperty>( this HtmlHelper<TModel> html, Expression<Func<TModel, TProperty>> expression, IEnumerable<SelectListItem> selectList, object htmlAttributes) { ... }
Visto che, in fin dei conti, dobbiamo realizzare un box di testo, questo metodo contiene tutti i parametri che troviamo nell'helper TextBoxFor (sia l'expression che l'oggetto htmlAttributes), ma richiede anche una lista di SelectListItem, che poi utilizzeremo per popolare l'elenco a scomparsa.
Passando all'implementazione, il nostro primo compito è quello di generare un id univoco per la datalist, e di referenziarlo dalla TextBox:
var listId = ExpressionHelper.GetExpressionText(expression) + "_dataList"; if (htmlAttributes == null) htmlAttributes = new object(); RouteValueDictionary dictionary = new RouteValueDictionary(htmlAttributes); dictionary.Add("list", listId); var input = html.TextBoxFor(expression, dictionary);
A questo punto non ci resta che creare, tramite TagBuilder, la parte di markup mancante, ossia quella relativa al tag DataList:
var dataList = new TagBuilder("DataList"); dataList.GenerateId(listId); StringBuilder items = new StringBuilder(); foreach (var item in selectList) { items.AppendLine(ItemToOption(item)); } dataList.InnerHtml = items.ToString(); return new MvcHtmlString(input + dataList.ToString());
Nel codice precedente, abbiamo sfruttato il medesimo listId per associare questo identificativo alla DataList. Successivamente, per ogni elemento SelectListItem fornito, generiamo il corrispondente tag option, da aggiungere all'InnerHtml della DataList stessa. Questo compito è eseguito dal metodo ItemToOption:
private static string ItemToOption(SelectListItem item) { TagBuilder builder = new TagBuilder("option"); builder.MergeAttribute("value", item.Value); builder.SetInnerText(item.Text); return builder.ToString(TagRenderMode.Normal); }
Con questi semplici passaggi, siamo stati in grado di confezionare un HtmlHelper che rende davvero immediato l'utilizzo di questo nuovo elemento, come possiamo notare dal codice seguente:
<div class="col-md-10"> @Html.DataListFor(model => model.Title, this.Model.AvailableTitles, null) </div>
Commenti
Per inserire un commento, devi avere un account.
Fai il login e torna a questa pagina, oppure registrati alla nostra community.
Approfondimenti
Utilizzare i primary constructor di C# per inizializzare le proprietà
Utilizzare l nesting nativo dei CSS
Popolare una classe a partire dal testo, con Semantic Kernel e ASP.NET Core Web API
Eseguire i worklow di GitHub su runner potenziati
Ordinare randomicamente una lista in C#
Autenticarsi in modo sicuro su Azure tramite GitHub Actions
Conoscere il rendering Server o WebAssembly a runtime in Blazor
Collegare applicazioni server e client con .NET Aspire
Filtering sulle colonne in una QuickGrid di Blazor
Creare una libreria CSS universale - Rotazione degli elementi
Garantire la provenienza e l'integrità degli artefatti prodotti su GitHub
Migliorare la scalabilità delle Azure Function con il Flex Consumption