p2p.wrox.com Forums

p2p.wrox.com Forums (http://p2p.wrox.com/index.php)
-   BOOK: Professional ASP.NET MVC 3 (http://p2p.wrox.com/forumdisplay.php?f=649)
-   -   Chpt 8 Ajax Search Form (http://p2p.wrox.com/showthread.php?t=85347)

JackHerr October 13th, 2011 05:08 PM

Chpt 8 Ajax Search Form
 
I am having trouble getting the Ajax search form in Chpt 8 to work. Instead of the search results appearing in the Home page, as they do for the non-Ajax search in Chpt 5, they appear in a separate/new page with no styling (for which I created no view). The book indicates that the form will replace the UpdateTargetId="searchresults", citing on page 191 that "in this example, you replace an element with the id of searchresults." I did not find anywhere in the example code such an id, and I therefore don't have it in my code. Is this the problem? Do I need to create an element somewhere with this id, and if so, what element and where? I am using a successfully completed Music Store MVC 3.0 tutorial per the .pdf downloaded from the asp.net website.

I would appreciate any help you can give me.

Here are the relevant classes, with some slight modifications from the code in the book, with _Layout.cshtml containing working code from the tutorial:

_Layout:
Code:

<!DOCTYPEhtml>
<
html>
<
head>
<title>@ViewBag.Title</title>
<linkhref="@Url.Content("~/Content/Site.css")"rel="stylesheet"type="text/css"/>
<linkhref="@Url.Content("~/Content/themes/base/jquery-ui.css")"rel="stylesheet"type="text/css"/>
<scriptsrc="@Url.Content("~/Scripts/jquery-1.5.1.min.js")"type="text/javascript"></script>
<scriptsrc="@Url.Content("~/Scripts/jquery.unobrusive-ajax.min.js")"type="text/javascript"></script>
<scriptsrc="@Url.Content("~/Scripts/jquery-ui.min.js")"type="text/javascript"></script>
<scriptsrc="@Url.Content("~/Scripts/MusicScripts.js")"type="text/javascript"></script>
</
head>
<
body>
<divid="header">
<h1>
<ahref="/">ASP.NET MVC MUSIC STORE</a></h1>
<ulid="navlist">
<liclass="first"><ahref="@Url.Content("~")"id="current">Home</a></li>
<li><ahref="@Url.Content("~/Store/")">Store</a></li>
<li>
@{Html.RenderAction("CartSummary", "ShoppingCart");}
</li>
<li><ahref="@Url.Content("~/StoreManager/")">Admin</a></li>
</ul>
</div>
@{Html.RenderAction("GenreMenu", "Store");}
<divid="main">
@RenderBody()
</div>
<divid="footer">
built with <ahref="http://asp.net/mvc">ASP.NET MVC 3</a>
</div>
</
body>
</
html>
>

Index view in Home:
Code:

@{
ViewBag.Title =
"Index";
}
<h2>
This is the Home Page</h2>
@using (Html.BeginForm("Search", "Home", FormMethod.Get))
{
<inputtype="text"name="q"/>
<inputtype="submit"value="Search"/>
}
@
using (Ajax.BeginForm("ArtistSearch", "Home", newAjaxOptions
{
InsertionMode =
InsertionMode.Replace,
HttpMethod =
"GET",
OnFailure =
"searchFailed",
LoadingElementId=
"ajax-loader",
UpdateTargetId =
"searchresults"
}))
{
<inputtype="text"name="q"/>
<inputtype="submit"value="Search"/>
<imgalt=""id="ajax-loader"src="@Url.Content("~/Content/Images/ajax-loader.gif")"style="display:none"/>
}

ActionResult in Home controller:
Code:

publicActionResult ArtistSearch(string q)
{
var artists = storeDB.Artists.Where(a => a.Name.Contains(q)).ToList();
return PartialView(artists);
}

ArtistSearch partial view:
Code:

@model IEnumerable<MvcMusicStore.Models.Artist>
<divid="searchresults">
<table>
<tr>
<th>
Name
</th>
</tr>
@foreach (var item in Model)
{
<tr>
<td>
@Html.DisplayFor(modelItem => item.Name)
</td>
</tr>
}
</table>
</
div>

Script in MusicScripts.js:
Code:

function searchFailed() { $("#searchresults").html("Problem with search."); }

JackHerr October 14th, 2011 11:36 AM

Progress. Using NuGet, I downloaded the partial code for the Ajax Form and the Autocomplete. I have been able to get the form to work -- but not the autocomplete.

First, I had to change the references to jquery to 1.5.1 (which I should have known since the same issue arose in the tutorial).

Second, I corrected the ref cited on page 187 to unobtrusive jquery from two "/Scripts" to one (which I should have detected from the actual file path names in the project script files).

Third, I added a null ref to an alt source in the Ajax form helper in the Home Index view to avoid a highlighted error as follows (page 190): <img alt="" id="ajax-loader" . . . etc.

Fourth, I added the <div id="searchresults"></div> in the Home Index view for the helper to put the return results in.

This all made the form itself work. The following, though, for the autocomplete seems to comply with the book and the download, but didn't work:

First, I changed reference to ui as "jquery-ui-1.8.11.min.js" not "jquery-ui.min.js" (page 199). Downloaded code alerted me there.

Second, I changed to ref to content themes from "jquery-ui.css" (which is on page 200) to "jquery.ui.all.css" per the downloaded code. This didn't work, so I changed "all" to "autocomlete", which also didn't work.

Third, I wrapped the jQuery code in the MusicScripts.js cited on page 201 in "$(function(){. . . insert code here . . .});" per the download. The download did not have the text "input" as cited in the first line of the code on page 201. I tried it both ways, no joy either time.

I put the script ref's exactly as in the download, and also tried putting them all in the Home _Layout view. Neither worked.

So, I have my code exactly as the download but the autocomplete doesn't work. The form works once a value is entered and the search button is clicked.

JackHerr October 14th, 2011 11:39 AM

PS. I also corrected my misspelling of unobtrusive (see original post)!!

AdmiringWorm October 14th, 2011 01:32 PM

regarding the autocomplete, from what I can see from the source in index, you have forgotten to add the data-autocomplete-source attribute:

Code:

<input type="text" name="q" data-autocomplete-source="@Url.Action("QuickSearch", "Home")" />
also the script inside the musicscript file regarding autocomplete should be:

Code:

$("input[data-autocomplete-source]").each(function () {
        var target = $(this);
        target.autocomplete({ source: target.attr("data-autocomplete-source") });
    });

OR

Code:

$(function() {
        $("input[data-autocomplete-source]").each(function () {
        var target = $(this);
        target.autocomplete({ source: target.attr("data-autocomplete-source") });
    });
});

using the first alternative would require you do place the MusicScripts.js reference below the input textbox (either in _Layout below @RenderBody()), or anywhere below the textbox in the index page.

Also make sure you have "UnobtrusiveJavaScriptEnabled" enabled in the appSettings in web.config/app.config

JackHerr October 14th, 2011 02:22 PM

Please Look at Code to See What's Wrong
 
I think I have all of your suggestions covered. Here are the complete relevant code blocks. If you have time, please look at them to see where I have slipped up. Thanks.

_Layout view -- Please note that I elected to put all link and script references in this view, which the text seems to suggest will work.
Code:

<!DOCTYPEhtml>
<
html>
<
head>
<title>@ViewBag.Title</title>
<linkhref="@Url.Content("~/Content/Site.css")"rel="stylesheet"type="text/css"/>
<linkhref="@Url.Content("~/Content/themes/base/jquery.ui.all.css")"rel="stylesheet"type="text/css"/>
<scriptsrc="@Url.Content("~/Scripts/jquery-1.5.1.min.js")"type="text/javascript"></script>
<scriptsrc="@Url.Content("~/Scripts/jquery.unobtrusive-ajax.min.js")"type="text/javascript"></script>
<scriptsrc="@Url.Content("~/Scripts/jquery-ui-1.8.11.min.js")"type="text/javascript"></script>
<scriptsrc="@Url.Content("~/Scripts/MusicScripts.js")"type="text/javascript"></script>
</
head>
<
body>
<divid="header">
<h1>
<ahref="/">ASP.NET MVC MUSIC STORE</a></h1>
<ulid="navlist">
<liclass="first"><ahref="@Url.Content("~")"id="current">Home</a></li>
<li><ahref="@Url.Content("~/Store/")">Store</a></li>
<li>
@{Html.RenderAction("CartSummary", "ShoppingCart");}
</li>
<li><ahref="@Url.Content("~/StoreManager/")">Admin</a></li>
</ul>
</div>
@{Html.RenderAction("GenreMenu", "Store");}
<divid="main">
@RenderBody()
</div>
<divid="footer">
built with <ahref="http://asp.net/mvc">ASP.NET MVC 3</a>
</div>
</
body>
</
html>

Index View of Home Controller -- Please note addition now of the data-autocomplete-source attribute. Also, please note that I kept the simple search built earlier in the book. Both searches work. It is just the autocomplete feature that is not working.
Code:

@model List<MvcMusicStore.Models.Album>
@{
ViewBag.Title =
"Index";
}
<h2>
This is the Home Page</h2>
@using (Html.BeginForm("Search", "Home", FormMethod.Get))
{
<inputtype="text"name="q"/>
<inputtype="submit"value="Search Title"/>
}
@
using (Ajax.BeginForm("ArtistSearch", "Home", newAjaxOptions
{
InsertionMode =
InsertionMode.Replace,
HttpMethod =
"GET",
OnFailure =
"searchFailed",
LoadingElementId =
"ajax-loader",
UpdateTargetId =
"searchresults"
}))
{
<inputtype="text"name="q"data-autocomplete-source="@Url.Action("QuickSearch", "Home")"/>
<inputtype="submit"value="Search Artist"/>
<imgalt=""id="ajax-loader"src="@Url.Content("~/Content/Images/ajax-loader.gif")"style="display:none"/>
}
<divid="searchresults">
</
div>

Complete Home Controller -- Please note that I built the tutorial with a database-first implementation of the database, hence the difference in model name.
Code:

using System;
using System.Collections.Generic;
using System.Linq;
using System.Web;
using System.Web.Mvc;
using MvcMusicStore.Models;
namespace MvcMusicStore.Controllers
{
publicclassHomeController : Controller
{
MusicStoreEntitiesInModel storeDB = newMusicStoreEntitiesInModel();
//
// GET: /Home/
publicActionResult Index()
{
return View();
}
publicActionResult Search(string q)
{
var albums = storeDB.Albums.Include("Artist").Where(a => a.Title.Contains(q) || q == null).Take(10);
return View(albums);
}
publicActionResult QuickSearch(string term)
{
var artists = GetArtists(term).Select(a => new { value = a.Name });
return Json(artists, JsonRequestBehavior.AllowGet);
}
publicActionResult ArtistSearch(string q)
{
var artists = GetArtists(q);
return PartialView(artists);
}
privateList<Artist> GetArtists(string searchString)
{
return storeDB.Artists.Where(a => a.Name.Contains(searchString)).ToList();
}
}
}

MusicScripts.js -- Please note that I use the first of the two forms you suggest.
Code:

/// <reference path="jquery-1.5.1.js" />
/// <reference path="jquery-ui-1.8.11.js" />
$(function () {
$(
"input[data-autocomplete-source]").each(function () {
var target = $(this);
target.autocomplete({ source: target.attr(
"data-autocomplete-source") });
});
});
function searchFailed() { $("#searchresults").html("Sorry, there was a problem with the search."); }


AdmiringWorm October 14th, 2011 03:04 PM

hmm, this is really odd. I tried to reproduce your problem with the source you provided, and everything worked on my end.

Just to grasp at straws here:
Have you checked that the browser just have catched an old version of MusicScripts.js?

try reloading the browser with CTRL + R to download everything again.

if this does not work, then I'm afraid I'm out of suggestions, hopefully someone else can help you (I'll still will by trying to check of course)

JackHerr October 14th, 2011 03:21 PM

Holy Mackerel (sp?).

When I launched, then hit CTL+R, it worked. I then relaunched and it worked straight away. Can you explain what happened? Did my browser cache a version of the file, and keep it, thinking it didn't need to download it until I forced it to do so?

I also modified the Home Controller to return a JsonResult but either that or ActionResult now works.

Code:

publicJsonResult QuickSearch(string term)
{
var artists = GetArtists(term).Select(a => new { value = a.Name });
return Json(artists, JsonRequestBehavior.AllowGet);
}

Thank you so much!!

Jack Herr

AdmiringWorm October 14th, 2011 03:26 PM

Quote:

Originally Posted by JackHerr (Post 277431)
Holy Mackerel (sp?).

When I launched, then hit CTL+R, it worked. I then relaunched and it worked straight away. Can you explain what happened? Did my browser cache a version of the file, and keep it, thinking it didn't need to download it until I forced it to do so?

Thank you so much!!

Jack Herr

this is actually exactly what happened.
The browser cached the file so it would not have to download it again, I do not really know much about how the logic works, but I think it compares either the name of the file with the cached one, or the url it was downloaded from. and not the content of the file.

JackHerr October 14th, 2011 03:31 PM

I restarted my machine, relaunched VS 2010, and relaunched the project, and it worked perfectly.

Thank you again.


All times are GMT -4. The time now is 12:22 PM.

Powered by vBulletin®
Copyright ©2000 - 2020, Jelsoft Enterprises Ltd.
© 2013 John Wiley & Sons, Inc.