Compartilhar via


Tutorial: Adicionar preenchimento automático e sugestões usando o SDK do .NET

Saiba como implementar o preenchimento automático (consultas typeahead e resultados sugeridos) quando um usuário começa a digitar em uma caixa de pesquisa. Neste tutorial, mostraremos consultas autocompletadas e resultados sugeridos separadamente e, em seguida, juntos. Um usuário pode ter que digitar apenas dois ou três caracteres para localizar todos os resultados disponíveis.

Neste tutorial, você aprenderá como:

  • Adicionar sugestões
  • Adicionar realce às sugestões
  • Adicionar o preenchimento automático
  • Combinar preenchimento automático e sugestões

Visão geral

Este tutorial adiciona preenchimento automático e resultados sugeridos ao tutorial anterior Adicionar paginação aos resultados da pesquisa.

Uma versão concluída do código neste tutorial pode ser encontrada no seguinte projeto:

Pré-requisitos

Adicionar sugestões

Vamos começar com o caso mais simples de oferecer alternativas ao usuário: uma lista suspensa de resultados sugeridos.

  1. No arquivo index.cshtml, altere @id, da instrução TextBoxFor para azureautosuggest.

     @Html.TextBoxFor(m => m.searchText, new { @class = "searchBox", @id = "azureautosuggest" }) <input value="" class="searchBoxSubmit" type="submit">
    
  2. Seguindo esta instrução, após o fechamento </div>, insira esse script. Esse script utiliza o widget de preenchimento automático da biblioteca jQuery UI de código aberto para apresentar a lista suspensa 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>
    

    A ID "azureautosuggest" conecta o script acima à caixa de pesquisa. A opção de origem do widget é definida como um método Suggest, que chama a API Suggest com dois parâmetros de consulta: realce e difusa , ambos definidos como false nesta instância. Além disso, um mínimo de dois caracteres é necessário para disparar a pesquisa.

Adicionar referências a scripts jQuery à exibição

  1. Para acessar a biblioteca jQuery, altere a seção <head> do arquivo de visualização para o seguinte código:

    <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>
    
  2. Como estamos introduzindo uma nova referência jQuery, também precisamos remover ou comentar a referência jQuery padrão no arquivo _Layout.cshtml (na pasta Views/Shared). Localize as linhas a seguir e comente a primeira linha de script, conforme mostrado. Essa alteração evita referências conflitantes ao 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>
    

    Agora podemos usar as funções jQuery de preenchimento automático predefinidas.

Adicionar a ação Sugerir ao controlador

  1. No controlador "home", adicione a ação SuggestAsync (após a ação 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);
    }
    

    O parâmetro Size especifica quantos resultados retornar (se não for especificado, o padrão é 5). Um sugestor é especificado no índice de pesquisa quando o índice é criado. No índice de hotéis de exemplo hospedado pela Microsoft, o nome do sugestor é "sg" e pesquisa correspondências sugeridas exclusivamente no campo HotelName.

    A correspondência difusa permite que "coincidências aproximadas" sejam incluídas na saída, com até uma unidade de distância de edição. Se o parâmetro de realçar for definido como true, marcas HTML em negrito serão adicionadas à saída. Definiremos ambos os parâmetros como verdadeiros na próxima seção.

  2. Você pode receber alguns erros de sintaxe. Nesse caso, adicione as duas instruções using a seguir à parte superior do arquivo.

    using System.Collections.Generic;
    using System.Linq;
    
  3. Execute o aplicativo. Você obtém uma gama de opções quando você digita "po", por exemplo? Agora tente "pa".

    Digitar *po* revela duas sugestões

    Observe que as letras inseridas devem iniciar uma palavra e não simplesmente ser incluídas na palavra.

  4. No script de exibição, defina &fuzzy como true e execute o aplicativo novamente. Agora, insira "po". Observe que a pesquisa pressupõe que você errou uma letra.

    Digitar *pa* com fuzzy definido como verdadeiro

    Se você estiver interessado, a sintaxe de consulta Lucene no Azure Cognitive Search descreve em detalhes a lógica usada em buscas aproximadas.

Adicionar realce às sugestões

Podemos melhorar a aparência das sugestões para o usuário configurando o parâmetro de destaques como verdadeiro. No entanto, primeiro precisamos adicionar algum código à exibição para exibir o texto em negrito.

  1. Na exibição (index.cshtml), adicione o script a seguir após o 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>
    
  2. Agora, altere a ID da caixa de texto para que apareça da seguinte forma.

    @Html.TextBoxFor(m => m.searchText, new { @class = "searchBox", @id = "azuresuggesthighlights" }) <input value="" class="searchBoxSubmit" type="submit">
    
  3. Execute o aplicativo novamente e você deverá ver o texto inserido em negrito nas sugestões. Tente digitar "pa".

    digitar *pa* com realce

    A lógica usada no script de realce acima não é infalível. Se você inserir um termo que aparece duas vezes com o mesmo nome, os resultados em negrito não são exatamente o que você gostaria. Tente digitar "mo".

    Uma das perguntas que um desenvolvedor precisa responder é, quando um script está funcionando "bem o suficiente", e quando suas peculiaridades devem ser abordadas. Não levaremos o realce mais adiante neste tutorial, mas encontrar um algoritmo preciso é algo a ser considerado se o realce não for eficaz para seus dados. Para obter mais informações, consulte realce de resultados.

Adicionar o preenchimento automático

Outra variação, ligeiramente diferente das sugestões automáticas, é o preenchimento automático (às vezes chamado de "type-ahead") que conclui um termo de consulta. Novamente, começaremos com a implementação mais simples, antes de melhorar a experiência do usuário.

  1. Insira o script a seguir na exibição, seguindo seus scripts anteriores.

    <script>
        $("#azureautocompletebasic").autocomplete({
            source: "/Home/Autocomplete",
            minLength: 2,
            position: {
                my: "left top",
                at: "left-23 bottom+10"
            }
        });
    </script>
    
  2. Agora, altere o ID da caixa de texto para que ele fique da seguinte maneira.

    @Html.TextBoxFor(m => m.searchText, new { @class = "searchBox", @id = "azureautocompletebasic" }) <input value="" class="searchBoxSubmit" type="submit">
    
  3. No controlador principal, insira a ação AutocompleteAsync após a ação 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 a mesma função sugestão, chamada "sg", na pesquisa de preenchimento automático, assim como fizemos para sugestões (portanto, estamos apenas tentando autocompletar os nomes dos hotéis).

    Há uma variedade de configurações de AutocompleteMode, e estamos usando OneTermWithContext. Consulte a API de Preenchimento Automático para obter uma descrição das opções adicionais.

  4. Execute o aplicativo. Observe como o intervalo de opções exibido na lista suspensa é de palavras únicas. Tente digitar palavras começando com "re". Observe como o número de opções é reduzido à medida que mais letras são digitada.

    digitação com preenchimento automático básico

    Do jeito que está, o script de sugestões que você executou anteriormente provavelmente é mais útil do que esse script de preenchimento automático. Para tornar o preenchimento automático mais fácil de usar, considere usá-lo com os resultados sugeridos.

Combinar preenchimento automático e sugestões

Combinar preenchimento automático e sugestões é a mais complexa de nossas opções e provavelmente fornece a melhor experiência do usuário. O que queremos é exibir, junto ao texto que está sendo digitado, a primeira opção do Azure Cognitive Search para preenchimento automático do texto. Além disso, queremos um conjunto de sugestões como uma lista suspensa.

Há bibliotecas que oferecem essa funcionalidade , muitas vezes chamada de "preenchimento automático embutido" ou um nome semelhante. No entanto, vamos implementar esse recurso nativamente para que você possa explorar as APIs. Vamos começar a trabalhar no controlador primeiro neste exemplo.

  1. Adicione uma ação ao controlador que retorna apenas um resultado de preenchimento automático, juntamente com um número especificado de sugestões. Chamaremos esta ação AutoCompleteAndSuggestAsync. No controlador principal, adicione as seguintes ações, após suas outras novas ações.

    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);
    }
    

    Uma opção de preenchimento automático é retornada na parte superior da lista de resultados , seguida por todas as sugestões.

  2. Na visão, primeiro implementamos um truque para que uma palavra de preenchimento automático cinza claro seja renderizada logo abaixo do texto mais escuro sendo inserido pelo usuário. HTML inclui posicionamento relativo para essa finalidade. Altere a instrução TextBoxFor (e suas instruções de div <em torno de>) para o seguinte, observando que uma segunda caixa de pesquisa identificada como abaixo de está logo abaixo de nossa caixa de pesquisa normal, puxando essa caixa de pesquisa 39 pixels de sua localização padrão!

    <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 alterando o identificador novamente, para azureautocomplete neste caso.

  3. Na visualização, insira o script a seguir, depois de todos os scripts que você inseriu até agora. O script é longo e complexo devido à variedade de comportamentos de entrada que ele manipula.

    <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 como a função intervalo é usada para limpar o texto subjacente quando não corresponde mais ao que o usuário está digitando e também para definir a mesma caixa (maiúscula ou minúscula) em que o usuário está digitando (como "pa" corresponde a "PA", "pA", "Pa" ao pesquisar), de modo que o texto sobreposto seja limpo.

    Leia os comentários no script para obter uma compreensão mais completa.

  4. Por fim, precisamos fazer um pequeno ajuste em duas classes HTML para torná-las transparentes. Adicione a linha a seguir às classes searchBoxForm e searchBox, no arquivo hotels.css.

    background: rgba(0,0,0,0);
    
  5. Agora, execute o aplicativo. Insira "pa" na caixa de pesquisa. Você recebe "palácio" como sugestão de preenchimento automático, junto com dois hotéis que contêm "pa"?

    Digitar com preenchimento automático embutido e sugestões

  6. Tente usar a tecla Tab para aceitar a sugestão de preenchimento automático e tente selecionar sugestões usando as teclas de direção e a tecla Tab, e tente novamente usando o mouse e somente um clique. Verifique se o script lida perfeitamente com todas essas situações.

    Você pode decidir que é mais simples carregar uma biblioteca que oferece esse recurso para você, mas agora você sabe pelo menos uma maneira de obter o preenchimento automático integrado para funcionar.

Principais pontos

Considere as seguintes conclusões deste projeto:

  • O preenchimento automático (também conhecido como "type-ahead") e sugestões podem permitir que o usuário digite apenas algumas chaves para localizar exatamente o que deseja.
  • O preenchimento automático e as sugestões que trabalham em conjunto podem fornecer uma experiência avançada do usuário.
  • Sempre teste funções de preenchimento automático com todas as formas de entrada.
  • Usar a função setInterval pode ser útil para verificar e corrigir elementos da interface do usuário.

Próximas etapas

No próximo tutorial, veremos outra maneira de melhorar a experiência do usuário, usando facetas para restringir pesquisas com um único clique.

Tutorial C#: Use facetas para ajudar na navegação – do Azure Cognitive Search