Nota:
El acceso a esta página requiere autorización. Puede intentar iniciar sesión o cambiar directorios.
El acceso a esta página requiere autorización. Puede intentar cambiar los directorios.
Aprende a implementar el autocompletado (consultas predictivas y resultados sugeridos) cuando un usuario empieza a escribir en un cuadro de búsqueda. En este tutorial, mostraremos las consultas autocompletadas y los resultados sugeridos por separado y, a continuación, juntos. Un usuario solo puede tener que escribir dos o tres caracteres para buscar todos los resultados que están disponibles.
En este tutorial, aprenderá a:
- Adición de sugerencias
- Agregar resaltado a las sugerencias
- Adición de la función Autocompletar
- Combinar autocompletar y sugerencias
Información general
En este tutorial se añade la función de autocompletado y los resultados sugeridos al tutorial anterior Añadir paginación a los resultados de búsqueda.
En el proyecto siguiente se puede encontrar una versión finalizada del código de este tutorial:
Prerrequisitos
- Solución 2a-add-paging (GitHub). Este proyecto puede ser su propia versión compilada a partir del tutorial anterior o una copia de GitHub.
Adición de sugerencias
Comencemos con el caso más sencillo de ofrecer alternativas al usuario: una lista desplegable de resultados sugeridos.
En el archivo index.cshtml, cambie
@idla instrucción TextBoxFor a azureautosuggest.@Html.TextBoxFor(m => m.searchText, new { @class = "searchBox", @id = "azureautosuggest" }) <input value="" class="searchBoxSubmit" type="submit">A continuación, después de la declaración, después del </div> de cierre, escriba este script. Este script aprovecha el widget Autocompletar de la biblioteca de interfaz de usuario de jQuery de código abierto para presentar la lista desplegable de resultados sugeridos.
<script> $("#azureautosuggest").autocomplete({ source: "/Home/SuggestAsync?highlights=false&fuzzy=false", minLength: 2, position: { my: "left top", at: "left-23 bottom+10" } }); </script>El identificador
"azureautosuggest"conecta el script anterior al cuadro de búsqueda. La opción de origen del widget se establece en un método Suggest que llama a la API Suggest con dos parámetros de consulta: resaltados y aproximados, ambos establecidos en false en esta instancia. Además, se necesita un mínimo de dos caracteres para desencadenar la búsqueda.
Adición de referencias a scripts de jQuery a la vista
Para acceder a la biblioteca de jQuery, cambie la <sección principal> del archivo de vista por el código siguiente:
<head> <meta charset="utf-8"> <title>Typeahead</title> <link href="https://code.jquery.com/ui/1.12.1/themes/start/jquery-ui.css" rel="stylesheet"> <script src="https://code.jquery.com/jquery-1.10.2.js"></script> <script src="https://code.jquery.com/ui/1.12.1/jquery-ui.js"></script> <link rel="stylesheet" href="~/css/hotels.css" /> </head>Dado que estamos introduciendo una nueva referencia de jQuery, también es necesario quitar o comentar la referencia de jQuery predeterminada en el archivo _Layout.cshtml (en la carpeta Views/Shared ). Localice las siguientes líneas y comente la primera línea de script como se indica. Este cambio evita conflictos de referencias a jQuery.
<environment include="Development"> <!-- <script src="~/lib/jquery/dist/jquery.js"></script> --> <script src="~/lib/bootstrap/dist/js/bootstrap.js"></script> <script src="~/js/site.js" asp-append-version="true"></script> </environment>Ahora podemos usar las funciones predefinidas de autocompletar de jQuery.
Agregar la acción Sugerir al controlador
En el controlador principal, agregue la acción SuggestAsync (después de la acción PageAsync ).
public async Task<ActionResult> SuggestAsync(bool highlights, bool fuzzy, string term) { InitSearch(); // Setup the suggest parameters. var options = new SuggestOptions() { UseFuzzyMatching = fuzzy, Size = 8, }; if (highlights) { options.HighlightPreTag = "<b>"; options.HighlightPostTag = "</b>"; } // Only one suggester can be specified per index. It is defined in the index schema. // The name of the suggester is set when the suggester is specified by other API calls. // The suggester for the hotel database is called "sg", and simply searches the hotel name. var suggestResult = await _searchClient.SuggestAsync<Hotel>(term, "sg", options).ConfigureAwait(false); // Convert the suggested query results to a list that can be displayed in the client. List<string> suggestions = suggestResult.Value.Results.Select(x => x.Text).ToList(); // Return the list of suggestions. return new JsonResult(suggestions); }El parámetro Size especifica cuántos resultados se van a devolver (si no se especifica, el valor predeterminado es 5). Se especifica un proveedor de sugerencias en el índice de búsqueda cuando se crea el índice. En el índice de hoteles de ejemplo hospedado por Microsoft, el nombre del proveedor de sugerencias es "sg" y busca coincidencias sugeridas exclusivamente en el campo HotelName .
La coincidencia aproximada permite incluir "coincidencias parciales" en el resultado, hasta una distancia de edición. Si el parámetro highlights se establece en true, las etiquetas HTML en negrita se agregan a la salida. Estableceremos ambos parámetros en true en la sección siguiente.
Podrías encontrar algunos errores de sintaxis. Si es así, agregue las dos instrucciones using siguientes a la parte superior del archivo.
using System.Collections.Generic; using System.Linq;Ejecute la aplicación. ¿Obtiene una variedad de opciones al escribir "po", por ejemplo? Ahora prueba "pa".
Tenga en cuenta que las letras que escriba deben iniciar una palabra y no simplemente incluirse dentro de la palabra.
En el script de vista, establezca &fuzzy en true y vuelva a ejecutar la aplicación. Ahora escriba "po". Ten en cuenta que la búsqueda supone que te equivocaste en una letra.
Si está interesado, la sintaxis de consulta de Lucene en Azure Cognitive Search describe la lógica que se usa en búsquedas aproximadas en detalle.
Agregar resaltado a las sugerencias
Podemos mejorar la apariencia de las sugerencias al usuario estableciendo el parámetro highlights en true. Sin embargo, primero es necesario agregar código a la vista para mostrar el texto en negrita.
En la vista (index.cshtml), agregue el siguiente script después del script
"azureautosuggest"descrito anteriormente.<script> var updateTextbox = function (event, ui) { var result = ui.item.value.replace(/<\/?[^>]+(>|$)/g, ""); $("#azuresuggesthighlights").val(result); return false; }; $("#azuresuggesthighlights").autocomplete({ html: true, source: "/home/suggest?highlights=true&fuzzy=false&", minLength: 2, position: { my: "left top", at: "left-23 bottom+10" }, select: updateTextbox, focus: updateTextbox }).data("ui-autocomplete")._renderItem = function (ul, item) { return $("<li></li>") .data("item.autocomplete", item) .append("<a>" + item.label + "</a>") .appendTo(ul); }; </script>Ahora cambie el identificador del cuadro de texto para que lea lo siguiente.
@Html.TextBoxFor(m => m.searchText, new { @class = "searchBox", @id = "azuresuggesthighlights" }) <input value="" class="searchBoxSubmit" type="submit">Vuelva a ejecutar la aplicación y debería ver el texto escrito en negrita en las sugerencias. Intente escribir "pa".
La lógica que se usa en el script de resaltado anterior no es infalible. Si escribe un término que aparece dos veces en el mismo nombre, los resultados en negrita no son exactamente lo que desea. Intente escribir "mo".
Una de las preguntas que debe responder un desarrollador es cuando un script funciona "lo suficientemente bien" y cuándo debe abordarse sus peculiaridades. No profundizaremos más en el resaltado en este tutorial, pero considerar un algoritmo preciso podría ser necesario si el resaltado no resulta eficaz para tus datos. Para obtener más información, vea Resaltado de resultados.
Adición de la función Autocompletar
Otra variación, ligeramente diferente de las sugerencias, es la autocompletar (a veces denominada "escritura anticipada") que completa un término de consulta. De nuevo, empezaremos con la implementación más sencilla, antes de mejorar la experiencia del usuario.
Introduzca el siguiente script en la vista, siguiendo los scripts anteriores.
<script> $("#azureautocompletebasic").autocomplete({ source: "/Home/Autocomplete", minLength: 2, position: { my: "left top", at: "left-23 bottom+10" } }); </script>Ahora cambie el identificador del cuadro de texto, para que lea como se muestra a continuación.
@Html.TextBoxFor(m => m.searchText, new { @class = "searchBox", @id = "azureautocompletebasic" }) <input value="" class="searchBoxSubmit" type="submit">En el controlador principal, escriba la acción AutocompleteAsync después de la acción SuggestAsync .
public async Task<ActionResult> AutoCompleteAsync(string term) { InitSearch(); // Setup the autocomplete parameters. var ap = new AutocompleteOptions() { Mode = AutocompleteMode.OneTermWithContext, Size = 6 }; var autocompleteResult = await _searchClient.AutocompleteAsync(term, "sg", ap).ConfigureAwait(false); // Convert the autocompleteResult results to a list that can be displayed in the client. List<string> autocomplete = autocompleteResult.Value.Results.Select(x => x.Text).ToList(); return new JsonResult(autocomplete); }Observe que estamos usando la misma función del proveedor de sugerencias , denominada "sg", en la búsqueda de autocompletar como hicimos para las sugerencias (por lo que solo intentamos autocompletar los nombres de hotel).
Hay varias configuraciones de AutocompleteMode, y estamos usando OneTermWithContext. Consulte la API de Autocompletar para obtener una descripción de las opciones adicionales.
Ejecute la aplicación. Observe cómo el intervalo de opciones que se muestran en la lista desplegable son palabras únicas. Intente escribir palabras a partir de "re". Observe cómo se reduce el número de opciones a medida que se escriben más letras.
En su estado actual, el programa de sugerencias que ejecutó antes probablemente es más útil que este programa de autocompletar. Para que el autocompletado sea más fácil de usar, considere usarlo con los resultados sugeridos.
Combinar autocompletar y sugerencias
La combinación de autocompletar y sugerencias es la más compleja de nuestras opciones y probablemente proporciona la mejor experiencia de usuario. Lo que queremos es mostrar, de forma integrada con el texto que se está escribiendo, la primera opción de Azure Cognitive Search para autocompletar el texto. Además, queremos una variedad de sugerencias como una lista desplegable.
Hay bibliotecas que ofrecen esta funcionalidad, a menudo llamada "autocompletar en línea" o un nombre similar. Sin embargo, vamos a implementar de forma nativa esta característica para que pueda explorar las API. Vamos a empezar a trabajar en el controlador primero en este ejemplo.
Agregue una acción al controlador que devuelva solo un resultado de autocompletar, junto con un número especificado de sugerencias. Llamaremos a esta acción AutoCompleteAndSuggestAsync. En el controlador principal, agregue la siguiente acción, siguiendo las demás acciones nuevas.
public async Task<ActionResult> AutoCompleteAndSuggestAsync(string term) { InitSearch(); // Setup the type-ahead search parameters. var ap = new AutocompleteOptions() { Mode = AutocompleteMode.OneTermWithContext, Size = 1, }; var autocompleteResult = await _searchClient.AutocompleteAsync(term, "sg", ap); // Setup the suggest search parameters. var sp = new SuggestOptions() { Size = 8, }; // Only one suggester can be specified per index. The name of the suggester is set when the suggester is specified by other API calls. // The suggester for the hotel database is called "sg" and simply searches the hotel name. var suggestResult = await _searchClient.SuggestAsync<Hotel>(term, "sg", sp).ConfigureAwait(false); // Create an empty list. var results = new List<string>(); if (autocompleteResult.Value.Results.Count > 0) { // Add the top result for type-ahead. results.Add(autocompleteResult.Value.Results[0].Text); } else { // There were no type-ahead suggestions, so add an empty string. results.Add(""); } for (int n = 0; n < suggestResult.Value.Results.Count; n++) { // Now add the suggestions. results.Add(suggestResult.Value.Results[n].Text); } // Return the list. return new JsonResult(results); }Se devuelve una opción de autocompletar en la parte superior de la lista de resultados , seguida de todas las sugerencias.
En la vista, primero implementamos un truco para que la palabra de autocompletación gris clara se represente justo debajo del texto en negrita que el usuario escribe. HTML incluye posicionamiento relativo para este propósito. Cambie la instrucción TextBoxFor (y las instrucciones <div> circundantes) a lo siguiente, teniendo en cuenta que hay un segundo cuadro de búsqueda, identificado como debajo, justo debajo de nuestro cuadro de búsqueda normal, moviendo este cuadro de búsqueda 39 píxeles desde su ubicación predeterminada.
<div id="underneath" class="searchBox" style="position: relative; left: 0; top: 0"> </div> <div id="searchinput" class="searchBoxForm" style="position: relative; left: 0; top: -39px"> @Html.TextBoxFor(m => m.searchText, new { @class = "searchBox", @id = "azureautocomplete" }) <input value="" class="searchBoxSubmit" type="submit"> </div>Observe que estamos cambiando de nuevo el identificador a azureautocomplete en este caso.
También en la vista, escriba el siguiente script, después de todos los scripts que haya escrito hasta ahora. El script es largo y complejo debido a la variedad de comportamientos de entrada que controla.
<script> $('#azureautocomplete').autocomplete({ delay: 500, minLength: 2, position: { my: "left top", at: "left-23 bottom+10" }, // Use Ajax to set up a "success" function. source: function (request, response) { var controllerUrl = "/Home/AutoCompleteAndSuggestAsync?term=" + $("#azureautocomplete").val(); $.ajax({ url: controllerUrl, dataType: "json", success: function (data) { if (data && data.length > 0) { // Show the autocomplete suggestion. document.getElementById("underneath").innerHTML = data[0]; // Remove the top suggestion as it is used for inline autocomplete. var array = new Array(); for (var n = 1; n < data.length; n++) { array[n - 1] = data[n]; } // Show the drop-down list of suggestions. response(array); } else { // Nothing is returned, so clear the autocomplete suggestion. document.getElementById("underneath").innerHTML = ""; } } }); } }); // Complete on TAB. // Clear on ESC. // Clear if backspace to less than 2 characters. // Clear if any arrow key hit as user is navigating the suggestions. $("#azureautocomplete").keydown(function (evt) { var suggestedText = document.getElementById("underneath").innerHTML; if (evt.keyCode === 9 /* TAB */ && suggestedText.length > 0) { $("#azureautocomplete").val(suggestedText); return false; } else if (evt.keyCode === 27 /* ESC */) { document.getElementById("underneath").innerHTML = ""; $("#azureautocomplete").val(""); } else if (evt.keyCode === 8 /* Backspace */) { if ($("#azureautocomplete").val().length < 2) { document.getElementById("underneath").innerHTML = ""; } } else if (evt.keyCode >= 37 && evt.keyCode <= 40 /* Any arrow key */) { document.getElementById("underneath").innerHTML = ""; } }); // Character replace function. function setCharAt(str, index, chr) { if (index > str.length - 1) return str; return str.substr(0, index) + chr + str.substr(index + 1); } // This function is needed to clear the "underneath" text when the user clicks on a suggestion, and to // correct the case of the autocomplete option when it does not match the case of the user input. // The interval function is activated with the input, blur, change, or focus events. $("#azureautocomplete").on("input blur change focus", function (e) { // Set a 2 second interval duration. var intervalDuration = 2000, interval = setInterval(function () { // Compare the autocorrect suggestion with the actual typed string. var inputText = document.getElementById("azureautocomplete").value; var autoText = document.getElementById("underneath").innerHTML; // If the typed string is longer than the suggestion, then clear the suggestion. if (inputText.length > autoText.length) { document.getElementById("underneath").innerHTML = ""; } else { // If the strings match, change the case of the suggestion to match the case of the typed input. if (autoText.toLowerCase().startsWith(inputText.toLowerCase())) { for (var n = 0; n < inputText.length; n++) { autoText = setCharAt(autoText, n, inputText[n]); } document.getElementById("underneath").innerHTML = autoText; } else { // The strings do not match, so clear the suggestion. document.getElementById("underneath").innerHTML = ""; } } // If the element loses focus, stop the interval checking. if (!$input.is(':focus')) clearInterval(interval); }, intervalDuration); }); </script>Observe cómo se usa la función interval para borrar el texto subyacente cuando ya no coincide con lo que escribe el usuario y también para establecer el mismo caso (superior o inferior) que el usuario está escribiendo (como "pa" coincide con "PA", "pA", "Pa" al buscar), de modo que el texto superpuesto es ordenado.
Lea los comentarios del script para obtener una comprensión más completa.
Por último, es necesario realizar un ajuste menor en dos clases HTML para que sean transparentes. Agregue la siguiente línea a las clases searchBoxForm y searchBox , en el archivo hotels.css.
background: rgba(0,0,0,0);Ahora ejecute la aplicación. Escriba "pa" en el cuadro de búsqueda. ¿Recibes "palacio" como sugerencia de autocompletar, junto con dos hoteles que incluyen "pa" en su nombre?
Pruebe a usar la tecla de tabulación para aceptar la sugerencia de autocompletar e intente seleccionar sugerencias con las teclas de dirección y la tecla de tabulación, e inténtelo de nuevo con el ratón y un solo clic. Compruebe que el script controla todas estas situaciones de forma ordenada.
Puede decidir que es más sencillo cargar una biblioteca que le ofrezca esta funcionalidad, pero ahora al menos conoce una manera de que el autocompletado en línea funcione.
Conclusiones
Tenga en cuenta los siguientes aspectos de este proyecto:
- El autocompletado (también conocido como "búsqueda anticipada") y las sugerencias pueden permitir que el usuario escriba solo algunas teclas para localizar exactamente lo que quiere.
- El autocompletado y las sugerencias, cuando trabajan conjuntamente, pueden proporcionar una experiencia de usuario rica.
- Pruebe siempre las funciones de autocompletar con todas las formas de entrada.
- El uso de la función setInterval puede ser útil para comprobar y corregir elementos de la interfaz de usuario.
Pasos siguientes
En el siguiente tutorial, veremos otra manera de mejorar la experiencia del usuario, usando facetas para restringir las búsquedas con un solo clic.