net mvc framework asp asp.net-mvc razor asp.net-web-api asp.net-mvc-5 jquery-autocomplete

asp.net-mvc - framework - autocomplete mvc 5



Cómo diseñar una característica MVC5 Global Search en Layout.cshtml (1)

Esto suena como un buen caso de uso para Child Actions .

Este es un ejemplo básico con AJAX para que el usuario vea los resultados sin una recarga de página.

_Layout.cshtml

<div class="header"> @Html.Action("SearchWidget", "GlobalSearch") </div> @RenderBody() <script src="jquery.js" /> <script> $(".global-search-form").on("click", "button", function(e) { $.ajax({ url: "/GlobalSearch/Search", method: "GET", data: { item: $("input[name=''item'']").val() } }) .then(function(result) { $(".global-search-result").html(result); }); }); </script>

_Search.cshtml

<div class="global-search-widget"> <div class="globa-search-form"> <label for="item">Search For:</label> <input type="text" name="item" value="" /> <button type="button">Search</button> </div> <div class="global-search-results"></div> </div>

_SearchResults.cshtml

@model MyNamespace.SearchResults <div>Results</div> <ul> @foreach(var item in Model.Suggestions) { <li>@item</li> } </ul>

Resultados de la búsqueda

public class SearchResults { public List<string> Suggestions { get; set; } }

GlobalSearchController

[HttpGet] [ChildActionOnly] public ActionResult SearchWidget() { return PartialView("_Search"); } [HttpGet] public ActionResult Search(string item) { SearchResults results = searchService.Find(item); return PartialView("_SearchResults", results); }

Guardamos la declaración @model fuera de la página Diseño y lo movemos a la vista parcial de Acción infantil. Este ejemplo cargó el widget de búsqueda en Diseño pero puede usarlo en cualquier vista que desee.

Para simplificar las cosas aquí, el AJAX se activa mediante un botón, pero puede modificarlo para que se active con un cambio de texto demorado. El resultado también podría ser JSON en lugar de una vista parital: algunos complementos de Tipo por Delante del lado del cliente pueden manejar los resultados como JSON.

Si quieres navegar a una página de resultados

Puede soltar todo el script y convertir su widget a una forma adecuada.

@model MyNamespace.SearchForm @using(Html.BeginForm("Search", "GlobalSearch", FormMethod.Get, new { item = ViewBag.GlobalSearchKey }) { @Html.TextBoxFor(m => m.Item) <button type="submit">Search</button> }

Un modelo de búsqueda

public class SearchForm { public string Item { get; set; } }

Ajuste su diseño para pasar un parámetro al widget de búsqueda. Esto mantendrá la clave de búsqueda en la página de resultados.

@Html.Action("SearchWidget", "GlobalSearch", new { item = ViewBag.GlobalSearchKey })

La acción SearchWidget ahora pasa un parámetro para rellenar el formulario (si se proporciona).

[HttpGet] [ChildActionOnly] public ActionResult SearchWidget(string item) { var model = new SearchForm { Item = item ?? "" }; return PartialView("_Search", model); } [HttpGet] public ActionResult Search(SearchForm model) { var results = searchService.Find(model.Item); ViewBag.GlobalSearchKey = model.Item; // keep the same value for the form return View("SearchResults", results); // full view with layout }

Usamos el ViewBag para la clave de búsqueda, por lo que cualquier acción que utilice el diseño no tendrá que definir un modelo común.

Estoy tratando de implementar una función de "búsqueda global", que está disponible arriba de nuestro menú principal, en todas las Vistas dentro de nuestra aplicación. Se parece a esto:

La "búsqueda global" es un campo de entrada de autocompletar jQuery. Reside en nuestro _Layout.cshtml, que es una Vista compartida y se carga muchas veces por otras vistas. Básicamente, mostrará una lista de sugerencias automáticas para las palabras clave de búsqueda. Nuestra lista de sugerencias de palabras clave es de aproximadamente 6000 elementos.

Nuestro HomeController se ve así:

public class HomeController : Controller { public ActionResult Index() { return View(); } public ActionResult Home() { ViewBag.Message = " Home Page."; GlobalSearchController controller = new GlobalSearchController(); //_Layout.cshtml uses this for the auto-complete jQuery list var suggestions = controller.GetGlobalSearchSuggestions(); return View(suggestions); } public ActionResult SearchResults() { ViewBag.Message = "Search Results page."; GlobalSearchController controller = new GlobalSearchController(); var searchKeyword = "technology"; //SearchResults.html uses this for the search results data var results = controller.GetGlobalSearchResults(searchKeyword); ViewBag.SearchKeyword = searchKeyword; return View(results); } }

_Layout.cshtml usa este modelo:

@model MyApplication.Models.GlobalSearchSuggestions

SearchResults.cshtml utiliza este modelo:

@model IQueryable<MyApplication.Models.GlobalSearchResult>

Mi problema comienza cuando uso @model declarative en _Layout.cshtml.

Me sale un error como este:

Message = "El elemento del modelo pasado al diccionario es del tipo ''System.Web.Mvc.HandleErrorInfo'', pero este diccionario requiere un elemento de modelo de tipo ''MyApplication.Models.GlobalSearchSuggestions''."

Si elimino el modelo declarativo para _Layout.cshtml y recupero las "sugerencias" a través de otros medios (como AJAX), permitirá que SearchResults.cshtml funcione. No se produce ningún error Pero preferiría usar el modelo en lugar de AJAX. Entonces, si dejo el modelo declarativo en _Layout.cshtml, obtengo la excepción.

Tampoco puedo cargar las "sugerencias" desde ninguna Vista que no sea Inicio. ¿Porqué es eso? Si voy a otra vista dentro de nuestra aplicación e intento realizar una "búsqueda global" desde nuestro widget _Layout.cshtml, no obtengo ninguna "sugerencia" o información en el autocompletado de jQuery. ¿Por qué solo funciona para la vista de Inicio y el controlador de Inicio?

¿Cómo evito esta excepción y uso los dos declaradores @model? ¿Y cómo puedo obtener _Layout.cshtml para que muestre constantemente las sugerencias en el campo de autocompletar (y no solo desde la página de inicio?)?

Cualquier ayuda es apreciada. ¡Gracias!