jQuery Autocomplete not working with Json data - asp.net-mvc

There are a whole bunch of tutorials out there explaining how to do this, eg here and here.
Looks real easy huh? Yet I've still somehow managed to waste half a day on it without getting anything working.
Eg: the following works absolutely fine
public ActionResult FindStuff(string q)
{
return Content("test");
}
$('#MyTextBox').autocomplete("MyController/FindStuff", {
parse: function(data) {
alert('parsing');
}
});
If I change it to the following, absolutely nothing happens.
public JsonResult FindStuff(string q)
{
return Json(new { name = "test" });
}
$('#MyTextBox').autocomplete("MyController/FindStuff", {
dataType: 'json', // I've also tried with this line commented out
parse: function(data) {
alert('parsing');
}
});
So it looks like the parse call is never being hit, i.e. I'm assuming the data load is blowing up somehow or thinks there is no data. Any ideas? Thanks.
p.s. it's the Jorn Zaefferer plugin here.

Make sure that you are returning an array and that you allow GET requests (in case your are using ASP.NET MVC 2.0):
public ActionResult FindStuff(string q)
{
return Json(new[] { new { name = "test" } }, JsonRequestBehavior.AllowGet);
}
And then follow the examples:
$('#MyTextBox').autocomplete("MyController/FindStuff", {
dataType: 'json',
parse: function (data) {
var rows = new Array();
for (var i = 0; i < data.length; i++) {
rows[i] = { data: data[i], value: data[i].name };
}
return rows;
},
formatItem: function (row, i, n) {
return row.name;
}
});
Works nicely.
Remark: FireBug helps diagnosing problems very quickly as it shows you exactly what AJAX requests are being sent and why they succeed or fail.

Related

Passing IEnumerable through Json

I'm making a "Like" button in a simple comment database MVC program.
I'm passins the ID of the comment through to a ActionResult in the HomeController when I hover over the "Like" button. The problem (I think) is that I don't know how to pass the IEnumerable list of Likes to the ajax.
The script and HTML part:
HTML:
Like this
Script:
$(".likes").hover(function (event) {
var Liker = { "CID": event.target.id };
$.ajax({
type: "POST",
contentType: "application/json; charset=utf-8",
url: "/Home/ShowLike/",
data: JSON.stringify(Liker),
dataType: "json",
success: function (data) {
$.each(data.Name, function (value) {
alert(value);
});
},
error: function (xhr, err) {
// Note: just for debugging purposes!
alert("readyState: " + xhr.readyState +
"\nstatus: " + xhr.status);
alert("responseText: " + xhr.responseText);
}
});
});
HomeController -> ShowLike
[HttpPost]
public ActionResult ShowLike(Liker ids)
{
LikesRepository lkrep = new LikesRepository();
IEnumerable<Like> list = lkrep.GetLikes(ids.CID);
return Json(list);
}
LikesRepository
public class LikesRepository
{
CommentDBDataContext m_db = new CommentDBDataContext();
public IEnumerable<Like> GetLikes(int iden)
{
var result = from c in m_db.Likes
where c.CID == iden
orderby c.Name ascending
select c;
return result;
}
public void AddLike(Like c)
{
m_db.Likes.InsertOnSubmit(c);
m_db.SubmitChanges(); //This works
}
}
After diving into the problem more, we found it was actually triggering an internal server error (500). This was caused by a circular reference from serializing the LINQ to SQL objects to JSON. This issue is discussed several times...
How to remove circular reference in Entity Framework?
How did I solve the Json serializing circular reference error?
Circular Reference exception with JSON Serialisation with MVC3 and EF4 CTP5w
An alternate solution is to return the data as lists of strings as they only required the names.

Pulling sql data into jquery autocomplete

I've looked for an answer to this, but not finding exactly what I'm looking for. So, please excuse if this has been answered any another thread.
I have a very large sql table that I'd like to use in a jquery autocomplete input field. I know I need to return that data as json formatted, just not sure the best way to accomplish this. This field is in an ASP.net MVC application.
I know I could probably do a php page that returns the result, but that seems a bit messy to me. Is the best way to go is by creating a web service that I call?
Thanks in advance for any help.
Here's some code as to how I have accomplished this. I am using the jquery UI plugin
The javascript on my View
$(function () {
$("#suburb").autocomplete({
source: function (request, response) {
$.ajax({
url: '#Url.Action("ManufacturerAutoComplete", "AutoComplete")', type: "POST", dataType: "json",
data: { searchText: request.term, maxResults: 10 },
success: function (data) {
response($.map(data, function (item) {
return { label: item.DisplayValue, value: item.Suburb, id: item.SuburbID, postcode: item.Postcode, state: item.State }
}))
}
})
},
select: function (event, ui) {
$("#state").val(ui.item.state);
$("#postcode").val(ui.item.postcode);
}
});
The input on my view
<input type="text" id="suburb" />
And finally the code from my Controller
[HttpPost]
public JsonResult ManufacturerAutoComplete(string searchText)
{
if (searchText.Length > 2)
{
var service = new SuburbSearchServiceClient();
var results = service.SearchSuburb(searchText, "Australia");
List<Suburbs> sList = new List<Suburbs>();
foreach (var item in results)
{
sList.Add(new Suburbs() { SuburbID = item.SuburbID, Suburb = item.Suburb, State = item.State, Postcode = item.Postcode, DisplayValue = item.Suburb + " - " + item.State + " - " + item.Postcode });
}
return Json(sList);
}
else
{
var data = string.Empty;
return Json(data);
}
}
You need to include the js and css from the jquery-ui plugin and the results of your auticomplete will be shown underneath the input element. As you can see from the JsonResult method, I am calling a web service to get my suburb data, but this could come from anywhere in reality.
Hope this helps.

ASP.NET MVC 3 Treeview

I need to display a Treeview in my MVC3 application. There will be a self referencing hierarchical table (Folders) and another table linked to it (Documents.) (So Folders can have N-subFolders and any folder/sub folder can have many documents.)
I have looked into using third party vendors such as Telerik, DJME and MVC Controls Toolkit. While all nice packages, I'm uneasy about the licences, and since i'm new to MVC (and programming in general,) I find their documentation lacking to get the right display working.
I've also looked at the heavily referenced blogs on TreeViews:
TreeViewHelper
and the Recursive Partial View
In addition to the other less referenced articles (The top 3 are also very informative):
http://tpeczek.com/2010/01/asynchronous-treeview-in-aspnet-mvc.html
http://mikehadlow.blogspot.com/2008/10/rendering-tree-view-using-mvc-framework.html
http://www.tek-tips.com/viewthread.cfm?qid=1637392&page=4
http://weblogs.asp.net/jigardesai/archive/2008/02/04/display-hierarchical-data-in-asp-net-mvc-framework.aspx
http://www.jigar.net/articles/viewhtmlcontent311.aspx
http://help.syncfusion.com/ug_82/ASP.NETMVCUI_Tools/CreatingATreeViewControl.html
I would like to use either the TreeViewHelper or the Recursive Partial View Method.
However, in the TreeViewHelper, I can't make it pull data from the second table (ie. I can only make it list the Files, but I'm not sure how to have it list the Documents for each File.)
For the Recursive Partial View, I'm still at a loss in how to convert this to MVC3 and also general implementation. I did find a post (forums.asp.net/t/1652809.aspx/1?treeview+with+mvc+3) that gives an explanation of how to convert a bit of it to MVC3, but i'm still unclear of what to do with it. I keep getting the error for the Partial view: Cannot implicitly Convert type 'void' to type 'object'
Like I said before I'm new to MVC3 and would like insight in which method would work best for my scenario and how to implement it.
In case anyone is wondering, the way I solved this problem was to use a recursive partial view. The problem I has having with it was that I didn't have the self referencing relationship set up in SQL/EF (I just had the ParentID field which wasn't linked to the Primary Key.) I also integrated jsTree as this has a lot of slick functionality such as search.
Like I said in the comment above, #Html.Action and #Html.Partial work instead of #Html.RenderAction and #Html.RenderPartial.
give a look to the edit/add/delete/node move templated TreeView of my Mvc Controls Toolkit here: http://mvccontrolstoolkit.codeplex.com/wikipage?title=TreeView
$(document).ready(function () {
BindChart();
});
function BindChart() {
$("#org").jOrgChart({
chartElement: '#chart',
dragAndDrop: true
});
}
$(".cardadd").live("click", function ()
{
var data = { id: 0 , ParentId:$(this).parent().data('cardid')};
OpenForminWindow('divfrmChartMember', 'divChartMember', 'frmChartMember', chart.ChartMember, data, '', 400, 1000);
});
$(".cardedit").live("click", function () {
var data = { id: $(this).parent().data('cardid')};
OpenForminWindow('divfrmChartMember', 'divChartMember', 'frmChartMember', chart.ChartMember, data, '', 400, 1000);
});
$(".cardremove").live("click", function () {
});
function OpenForminWindow(popupId, targetDivId, formid, url, data, callbackfunc, heigth, width) {
$.ajax({
type: "GET",
url: url,
data: data,
cache: false,
success: function (data) {
$('#' + targetDivId).html(data);
$('#' + formid).removeData('validator');
$('#' + formid).removeData('unobtrusiveValidation');
$('#' + formid).each(function () { $.data($(this)[0], 'validator', false); }); //enable to display the error messages
$.validator.unobtrusive.parse('#' + formid);
if (callbackfunc)
return callbackfunc();
}
});
$("#" + popupId).dialog({
modal: true,
height: heigth,
width: width,
beforeClose: function (event, ui) {
if (typeof refresh !== 'undefined' && refresh == true)
ReloadCurrentPage();
}
});
}
$('#frmChartMember').live('submit', function (e) {
SubmitAjaxForm($(this).attr('id'), chart.AddMember, ReloadChart);
e.preventDefault();
});
function SubmitAjaxForm(formId, url, callBack) {
$.ajax({
url: url,
type: 'post',
cache: false,
data: $('#' + formId).serialize(),
success: function (data) {
return callBack(data);
},
});
}
function ReloadChart(result) {
ClosePopup('divfrmChartMember');
$.ajax({
type: 'GET',
url: chart.ChartList,
cache: false,
success: function (result) {
$("#orgChart").html(result);
BindChart();
}
});
}
function ClosePopup(divid) {
$("#" + divid).dialog("close");
}
public class ChartController : Controller
{
//
// GET: /Chart/
ChartContext ctx = new ChartContext();
public ActionResult Index()
{
return View();
}
public ActionResult OrgChart()
{
return PartialView("_OrgChart", ctx.Cards.ToList());
}
public ActionResult ChartMember(int id, int? ParentId = null)
{
Card card = new Card();
if (id > 0)
card = ctx.Cards.Find(id);
else
card.ParentId = ParentId;
return PartialView("_ChartMember", card);
}
public ActionResult SaveMember(Card card)
{
if (card.id == 0)
ctx.Cards.Add(card);
else
ctx.Entry(card).State = System.Data.EntityState.Modified;
ctx.SaveChanges();
return Json(true, JsonRequestBehavior.AllowGet);
}
}

Deleting multiple records in ASP.NET MVC using jqGrid

How can you enable multiple selection in a jqGrid, and also allow users to delete all of the selected rows using an ASP.NET MVC controller?
I have set the delete url property to my /Controller/Delete method, and this works fine if one record is selected. However, if multiple records are selected, it attempts to send a null value back to the controller where an integer id is required.
You can, but you have to write code for it:
deleteSelected: function(grid) {
if (!grid.jqGrid) {
if (console) {
console.error("'grid' argument must be a jqGrid");
}
return;
}
var ids = grid.getGridParam('selarrrow');
var count = ids.length;
if (count == 0) return;
if (confirm("Delete these " + count + " records?")) {
$.post("DeleteMultiple",
{ ids: ids },
function() { grid.trigger("reloadGrid") },
"json");
}
}
[HttpPost]
public ActionResult DeleteMultiple(IEnumerable<Guid> ids)
{
if (!Request.IsAjaxRequest())
{
// we only support this via AJAX for now.
throw new InvalidOperationException();
}
if (!ids.Any())
{
// JsonError is an internal class which works with our Ajax error handling
return JsonError(null, "Cannot delete, because no records selected.");
}
var trans = Repository.StartTransaction();
foreach (var id in ids)
{
Repository.Delete(id);
}
trans.Commit();
return Json(true);
}
I want to update this for MVC2 and jquery 1.4.2, if you want to pass array parameters to mvc2:
var ids = $("#grid").getGridParam('selarrrow');
var postData = { values: ids };
if (confirm("Delete these " + count + " records?")) {
$.ajax({
type: "POST",
traditional: true,
url: "GridDBDemoDataDeleteMultiple",
data: postData,
dataType: "json",
success: function() { $("#grid").trigger("reloadGrid") }
});
}
check http://jquery14.com/day-01/jquery-14 ajax part
thx

How to get html returned from ActionResult in Controller

I am trying to implement a feature similar to the Related Questions on StackOverflow, I am doing this in MVC.
$().ready(function() {
var s = $("#Summary").val();
$("#Summary").blur(function() { QuestionSuggestions(s); });
});
function GetPastIssues(title) {
$(document).ready(function() {
$.ajax({ type: "POST",
url: "/Issue/GetSimilarIssues",
contentType: "application/json; charset=utf-8",
dataType: "xml",
dataType: "json",
data: "{'title':'" + title + "'}",
processData: false,
error: function(XMLHttpRequest, textStatus, errorThrown) { ajaxError(XMLHttpRequest, textStatus, errorThrown); },
success: function(xml) { ajaxFinish(xml); }
});
});
function ajaxFinish(xml) {
if (xml.d != "NO DATA") {
$('#question-suggestions').html(xml.d); //alert(xml.d); // This ALERT IS returning undefined
$('#question-suggestions').show();
}
}
The data being returned from my controller is 'undefined', as shown by the commented line in ajaxFinish.
What am I doing wrong?
//[AcceptVerbs(HttpVerbs.Get)]
[JsonParamFilter(Param = "title", TargetType = typeof(string))]
public ActionResult GetSimilarIssues(string title)
{
var issues = _db.GetSimilarIssues(title).ToList();
if (title == null || issues.Count() == 0)
return Json("NO DATA");
string retVal = null;
foreach (Issue issue in _db.GetSimilarIssues(title))
{
retVal += "<div class='answer-summary' style='width: 610px;'>";
retVal += "<a href='Issue.aspx?projid=" + issue.ProjectId.ToString() + "&issuetypeid=" + issue.IssueTypeId.ToString() +
"&issueid=" + issue.IssueId.ToString() + "'>";
retVal += issue.Summary;
retVal += "</a>";
retVal += "</div>";
}
return Json(retVal);
}
EDIT:
I think what will help me learn and implement a solution to my senario is if I can get some insight into how StackOverflow implements this javascript method:
function QuestionSuggestions() {
var s = $("#title").val();
if (s.length > 2) {
document.title = s + " - Stack Overflow";
$("#question-suggestions").load("/search/titles?like=" + escape(s));
}
Looks like a 'Search' folder in the Views folder and a PartialView called 'Title'. A SearchController.cs with the following method:
public ActionResult titles(string like)
{
// HOW TO IMPLEMENT THIS
return PartialView("Titles");
}
What goes in the Titles.ascx to display the html?
The purpose of JSON() is to return a JSON object -- not HTML. JSON object would be something like {html_value: "<li>blah" }. I'm not sure what your ajax request is expecting. If it is expecting JSON (you have dataType set twice), then you can do something like with an anonymous object:
return Json(new {html_value = retVal});
However, if you want to return HTML from your controller -- don't. That's exactly what a view is for. Create a view without any master page and do the loop and return the HTML that way. Ajax apps can take this HTML and drop it wherever necessary.
In fact, while you technically could do the above anonymous object (where you return the html inside of a json object), this isn't what it's for. If you want to use JSON you should be returning values, and letting the javascript on the client format it:
I'm not sure how "heavy" your issues object is, but assume that it only has the three fields you're using. In that case, do:
return Json(issues);
EDIT:
Well, I think "Best Practice" would be to return just the values via JSON and format within the javascript. I'm not familiar enough with JSON(), but I know it works (I'm using it for something simple). Try creating a simple issues object with just those three values and
return Json(issuesTxfr);
You don't need to use partialviews as you're calling from a controller. Just think of it as a very simple view. Here's an example of mine (please don't notice that I'm not following my own JSON advice -- this is from a while back and I now cringe looking at it for a few reasons):
public ActionResult Controls_Search_Ajax(string q, string el)
{
...
ViewData["controls"] = controls;
ViewData["el"] = el;
return View();
}
and
<%# Page Language="C#" AutoEventWireup="true" CodeBehind="Controls_Search_Ajax.aspx.cs" Inherits="IRSoxCompliance.Views.Edit.Controls_Search_Ajax" %>
<% var controls = ViewData.Get<IEnumerable<IRSoxCompliance.Models.Control>>("controls");
var el = ViewData.Get<String>("el");
if (controls != null)
{
foreach (var c in controls)
{
%><%= c.Control_ID %>***<%= c.Full_Control_Name %>***<li id="<%= el %>:li:<%= c.Control_ID %>"><span class="item"><%= Html.BreadCrumb(c, false) %></span><span class="actions">Remove</span><br></li>
<% }
}
%>
Note the fact that there is no master page specified.
You could always return HTML as a string. I'm not saying that this is necessarily the way to go, and I do agree with James Shannon about not using JSON to return HTML.
Phil Haack wrote an excellent article about this on his blog back in May.

Resources