Efficient way of using JQuery UI Autocomplete with ASP.NET - c#

I am using JQuery UI Autocomplete with my ASP.NET-C# Website.
JavaScript:
$(function () {
var availableTags = [
<%=GetAvaliableTags() %>
];
$("input.tag_list").autocomplete({
source: availableTags
});
});
C# Function in code-behind:
public string GetAvaliableTags()
{
var tags = new[] { "ActionScript", "Scheme" };
return String.Join(",", tags.Select(x => String.Format("\"{0}\"", x)));
}
This is working fine. But I have a doubt that if I fetch the big amount of tags from database, it will load all those tags on page load at once, making it slow. The efficient way that came to my mind is to use Ajax. But I am not a Ajax programmer and know little about it. Can any one please tell me how to do it with Ajax efficiently? How to call GetAvailableTags on demand?
UPDATE
I tried like this:
$(function () {
var availableTags = [function () {
$.ajax({
type: "POST",
contentType: "application/json; charset=utf-8",
url: "CreateTopic.aspx/GetAvaliableTags",
data: "{ 'key' : '" + $("input.tag_list").val() + "'}",
dataType: "json",
async: true,
dataFilter: function (data) { return data; },
success: function (data) {if (result.hasOwnProperty("d")) {
$("input.tag_list").autocomplete({
source: result.d
});
}
else {
// No .d; so just use result
$("input.tag_list").autocomplete({
source: result
});
});
}];
$("input.tag_list").autocomplete({
source: availableTags
});
});
Web Method equivalent of GetAvailableTags()
[System.Web.Services.WebMethod]
public static string GetAvaliableTags(string key)
{
var tags = new[] { "ActionScript", "Scheme" };
return String.Join(",", tags.Select(x => String.Format("\"{0}\"", x)));
}
But the Ajax call is not being fired. What can be the reason?

I would recommend using an ASP.NET AJAX Page Method on the server-side and have the jQuery .ajax() function call it to retrieve the data, like this:
Code-behind:
[WebMethod]
public static string GetAvailableTags()
{
// Put logic here to return list of tags (i.e. load from database)
var tags = new[] { "ActionScript", "Scheme" };
return String.Join(",", tags.Select(x => String.Format("\"{0}\"", x)));
}
Markup:
$(document).ready(function() {
$.ajax({
type: "POST",
url: "PageName.aspx/GetAvailableTags",
data: "{}",
contentType: "application/json; charset=utf-8",
dataType: "json",
success: function(result) {
if (result.hasOwnProperty("d")) {
// The .d is part of the result so reference it
// to get to the actual JSON data of interest
$("input.tag_list").autocomplete({
source: result.d
});
}
else {
// No .d; so just use result
$("input.tag_list").autocomplete({
source: result
});
}
}
});
});
Note: You will need to change the name of PageName.aspx to the name of your .aspx page. Also, the .d syntax was an anti-XSS protection put in by Microsoft in the ASP.NET 3.5 release of ASP.NET AJAX; therefore the check to see if the .d property is there or not.

I've got a good solution I implemented in an intranet app; it uses the jQuery UI Autocomplete function with an HttpHandler, and only searches for customers beginning with whatever's in the input; it's also only triggered when there are 3 or more characters typed. This means you're never retrieving the entire table, just a subset of it.
Firstly the HttpHandler. I won't go into the data-retrieval nuts and bolts cos you can probably figure out that part yourself. SUffice to say it calls a stored procedure to return customers whose name starts with (whatever was sent to the Handler), and returns a JSON-serialized array of matches to the Autocomplete handler.
using Newtonsoft.Json;
namespace Invoicing.HttpHandlers
{
[WebService(Namespace = "yournamespace/http-handlers/")]
[WebServiceBinding(ConformsTo = WsiProfiles.BasicProfile1_1)]
public class CustomerHandler : IHttpHandler
{
#region IHttpHandler Members
public bool IsReusable
{
get
{
return false;
}
}
public void ProcessRequest(HttpContext context)
{
// your data-retrieval logic here
// write json to context.Response
}
}
If you're not used to this approach I'll just quickly describe the JSON part.
Basically, I have a small wrapper-type object called "ResponseCustomer" because I only really need Customer ID and Name for the Autocomplete handler, not the complete Customer details: -
[Serializable]
public class ResponseCustomer
{
public int ID;
public string CustomerName;
}
IHttpHandler.ProcessRequest invokes my stored procedure, and transforms the results into an IList - this means the JSON returned is as lean as possible: -
public void ProcessRequest(HttpContext context)
{
string json = string.Empty;
// note the httpcontext.Request contains the search term
if (!string.IsNullOrEmpty(context.Request["term"]))
{
string searchTerm = context.Request["term"];
var customers = (data access component).CustomerSearch(searchTerm); // call Search stored proc
if (customers.Count != 0)
{
var transformList = new List<ResponseCustomer>();
for (int index = 0; index < customers.Count; index++)
{
transformList.Add(new ResponseCustomer
{
ID = customers[index].ID,
CustomerName = customers[index].CustomerName
});
}
// call Newtonsoft.Json function to serialize list into JSON
json = JsonConvert.SerializeObject(transformList);
}
}
// write the JSON (or nothing) to the response
context.Response.Write(json);
}
So far so good ?
Make sure this HttpHandler is wired into web.config (note you will have to do this differently for IIS6 than for IIS 7+): -
<system.web>
<!-- Custom HTTP handlers (IIS 6.0) -->
<httpHandlers>
<add path="customerHandler.ashx" verb="*" type="(namespace).(handler name), (assembly name)" />
i.e.
<add path="customerHandler.ashx" verb="*" type="MyProject.Handlers.CustomerHandler, MyProject" />
and for IIS7: -
<system.webServer>
<handlers>
<!-- Custom HTTP handlers (IIS7+) -->
<add name="customerHandler" preCondition="integratedMode" verb="*" path="customerHandler.ashx" type="(namespace).(handler name), (assembly name)"" />
Finally wire in the client-side, as you already know: -
HTML: -
<span>Customer</span>
<span class="ui-widget" style="display:inline-block">
<input id="txtCustomer" runat="server" clientidmode="Static" />
</span>
JS: -
$(function ()
{
$("#txtCustomer").autocomplete(
{
source: "customerHandler.ashx",
// note minlength, triggers the Handler call only once 3 characters entered
minLength: 3,
select: function (event, ui)
{
if (ui.item)
{
$("#txtCustomer").val(ui.item.CustomerName);
return false;
}
}
})
.data("autocomplete")._renderItem = function (ul, item)
{
// insert an item into the autocomplete dropdown (YMMV)
return $("<li></li>")
.data("item.autocomplete", item)
.append("<a><table cellpadding='0' cellspacing='0' border='0' width='250px'><tr><td width='200' valign='top' align='left'>"
+ item.CustomerName + "</td><td width='50px' valign='top' align='left'>[ID "
+ item.ID + "]</td></tr></table></a>")
.appendTo(ul);
};
});
Let me know if this helps, I can email you the relevant source files if you want.

If you want real time update of options
$(document).ready(function() {
$("textbox").autocomplete({
source: function (request, response) {
pageMethod.yourmethodname(request.term,onSuccess)
function onSuccess(Responce){
data = JSON.parse(Responce)
response($.map(data.d, function (item) {
return {
value: item
}
}
};

Related

How to pass an object to controller that contains an html string in .NetCore

I have an object that I want to pass to the controller. This object contains multiple strings that contains different sections of html code. My code worked for normal strings being passed, but once I tried adding html code, it failed to route anymore and I started getting 404s.
I tried changing the model to encode the string prior to passing it across however that failed completely. The following code works if the 3 strings contain no html code within. The sample strings are what I'm trying to get passed to my controller through the ajax call.
Javascript
var htmlString1 = '<div style="width: 100px;">Test html div 1</div>';
var htmlString2 = '<div style="width: 100px;">Test html div 2</div>';
var htmlString3 = '<div style="width: 100px;">Test html div 3</div>';
var htmlSectionContainer = {
htmlSection1: htmlString1,
htmlSection2: htmlString2,
htmlSection3: htmlString3
};
debugger;
$.ajax({
url: "#Url.Action("DisplayHtmlObjects", "Pages")",
method: "GET",
data: { "data": JSON.stringify(data) },
success: (response) => {
//do things
});
}
Model
public class HtmlSectionContainer
{
//Article ids for each of the pivot section intros.
public string htmlSection1{ get; set; }
public string htmlSection2 { get; set; }
public string htmlSection3 { get; set; }
}
Controller action
[HttpGet]
public IActionResult DisplayHtmlObjects(string data)
{
HtmlSectionContainer section = new HtmlSectionContainer();
if (data != null)
{
section = JsonConvert.DeserializeObject<HtmlSectionContainer>(data);
}
return View(section);
}
The actual result of the above html strings is a 404.
Trying to encode the individual strings inside the object still gives me a 404.
var htmlSectionContainer = {
htmlSection1: encodeURI(htmlString1),
htmlSection2: encodeURI(htmlString2),
htmlSection3: encodeURI(htmlString3)
};
Right now I'm not hitting the breakpoint at all inside the controller action. I should be able to hit the breakpoint, and in the data parameter see each of the 3 strings.
Also minor improvement, if possible, I'd prefer to have HtmlSectionContainer data as the parameter instead of string data in the controller action it data was null when I tried to do that.
There is a syntax error in this JS Code, i think it's getting the URL wrong
$.ajax({
url: "#Url.Action("DisplayHtmlObjects", "Pages"),
method: "GET",
data: { "data": JSON.stringify(data) },
success: (response) => {
//do things
});
}
It should be like this, you missed closing " it should be like this
$.ajax({
url: '#Url.Action("DisplayHtmlObjects", "Pages")',
method: "GET",
data: { "data": JSON.stringify(data) },
success: (response) => {
//do things
});
}
I have replaces the double quotation marks " to single quotation marks ' in this line
'#Url.Action("DisplayHtmlObjects", "Pages")'
Because inside the string you're using double quotations and that'll lead JS to think that the string has ended here.
And also you're passing data object JSON.stringify(data) but i don't see where that variable been declared and populated, you're using the variable htmlSectionContainer above to set the HTML data. so i guess it should be like this.
$.ajax({
url: '#Url.Action("DisplayHtmlObjects", "Pages")',
method: "GET",
data: { "data": JSON.stringify(htmlSectionContainer) },
success: (response) => {
//do things
});
}

Passing String into an API method with a Route Attribute

I have a method on an API Controller where I've set the route in an attribute, but I don't seem to be able to pass a string into this. When I try to hit this with an Ajax Request from the browser the console shows the following error:
BAD REQUEST - The request could not be processed by the server due to
invalid syntax.
The string I'm passing over is huge, but unfortunately is the only way I can import the data into the legacy application I'm working with. The test URL I'm using is (brace yourselves):
http://localhost:50915/api/job/import/ALMIG&sup3123456&sup32%20DAY%20ECONOMY&sup320170720&sup320170721&sup30&sup3&sup3&sup3&sup322&sup3Lara%20Croft%20Way&sup3Derby&sup3&sup3&sup3DE23%206GB&sup3Stuff&sup310&sup31&sup30&sup325&sup30&sup3&sup31%7CI%20Great%20Danger&sup30&sup30&sup30&sup3&sup3&sup30&sup3true&sup30&sup3&sup3&sup3&sup3&sup3&sup3&sup31&sup30&sup30&sup316&sup3Baden%20Road&sup3Stoke-on-Trent&sup3&sup3&sup3ST6%201SA&sup3&sup30&sup30&sup30&sup3&sup3&sup3&sup30&sup30&sup30&sup30&sup3&sup30&sup31&sup30&sup3&sup3&sup3&sup3&sup3&sup3&sup3&sup3&sup3&sup3&sup3Liane&sup307730044916&sup3Lara&sup307730044916&sup30&sup3d2f0acf7-50e1-4a53-96ce-4fffd00b1a96&sup30
And the method is defined as below, the code inside is irrelevant as I put a break point on the start of the method which is never hit:
[System.Web.Http.HttpPost]
[System.Web.Http.Route("api/job/import")]
public int TmsImport([FromBody]string import)
{
// do something...
}
Edit: Added Ajax Request
job.confirmBookings = function () {
// TMS Import
job.toConfirmRow.filter(function(obj) {
var jobRow = obj;
var strArray = [];
for (var prop in jobRow) {
if (jobRow.hasOwnProperty(prop)) {
strArray.push(jobRow[prop]);
}
}
var joinedStr = strArray.join(job.seperator);
$.ajax({
type: "POST",
crossDomain: true,
data: joinedStr,
url: job.tmsString,
contentType: "application/json;charset=utf-8",
success: function (data, status, xhr) {
console.log("TMS ID: " + data + " | " + status);
},
error: function (xhr) {
alert(xhr.responseText);
}
});
});
First format the route template correctly
[HttpPost]
[Route("api/job/import")] //Matches POST api/job/import
public int TmsImport([FromBody]string import) {
// do something...
}
Also you should post the data in the body of the request. If the payload is large then you do not want that in the URL

AJAX Return object contains d in asp.net web form

Hey guys Its a simple question but want to stop ajax return object contains d.
I asp.net web form
$.ajax({
type: "POST",
url: myurl,
data: JSON.stringify({value:"1"}),
contentType: "application/json; charset=utf-8",
dataType: "json",
success: function (result) {
//alert("i am in success");
console.log(result);
},
failure: function (response) {
console.log("I am in failure");
}
});
and
in .cs file
[WebMethod]
public static string getSpareParts(string value)
{
List<data> spareParts;
using (var db = new WaltonCrmEntities())
{
spareParts = db.SpareParts.Select(x => new data
{
id = x.ItemID,
text = x.ItemName
}).ToList();
}
JavaScriptSerializer js = new JavaScriptSerializer();
return js.Serialize(spareParts);
//return spareParts;
}
when result is return it will contain result in result.d but i want to stop this d thing .Simply result should be the result. Can anybody solve this.
There's not much you could do about this. That's the way ASP.NET WebMethods always serialize the response. The reason why Microsoft decided to wrap the response in this .d property is to protect against this particular JSON hijacking vulnerability. Of course you could always check in your success callback whether this property is present or not:
success: function (result) {
var data = result.hasOwnProperty('d') ? result.d : result;
console.log(data);
}
Also I would very strongly recommend against writing plumbing code in your WebMethod (like serialization stuff) and just return the proper object and let the infrastructure care about serialization:
[WebMethod]
public static List<data> getSpareParts(string value)
{
using (var db = new WaltonCrmEntities())
{
return db.SpareParts.Select(x => new data
{
id = x.ItemID,
text = x.ItemName
}).ToList();
}
}
Now inside your success callback you can directly work with this collection without the need to additionally JSON.parse it:
success: function (result) {
var data = result.hasOwnProperty('d') ? result.d : result;
for (var i = 0; i < data.length; i++) {
console.log('id: ' + data[i].id + ', text: ' + data[i].text);
}
}

How to obtain checked checkbox values on the serverside in c# from an ajax Http POST using web forms (not MVC)?

Here's my ajax call:
$(function () {
$("#chkFilter").on("click", "input", function (e)
{
var filterCheckboxes = new Array();
$("#chkFilter").find("input:checked").each(function () {
//console.log($(this).val()); //works fine
filterCheckboxes.push($(this).prop("name") + "=" + $(this).val());
console.log($(this).prop("name") + "=" + $(this).val());
//var filterCheckboxes = new Array();
//for (var i = 0; i < e.length; i++) {
// if (e[i].checked)
// filterCheckboxes.push(e[i].value);
//}
});
console.log("calling ajax");
$.ajax({
url: "/tools/oppy/Default",
type: "POST",
dataType: "json",
data: { filterValues: filterCheckboxes }, // using the parameter name
success: function (result) {
if (result.success) {
}
else {
}
}
});
});
});
And my server side code:
public partial class tools_oppy_Default : System.Web.UI.Page
{
...
protected void Page_Load(object sender, EventArgs e)
{
if (Request.HttpMethod == "POST")
{
string checkedBoxes = Request["filterValues"];
testLabel.Text = checkedBoxes;
}
I'm just trying to obtain the post URL with the appropriate checked values so I can parse it on the server. However, I'm having trouble obtaining the URL. The string checkedBoxes is supposed to hold a query string like name=value&name=value&name.... but when I test it, the testLabel doesn't show anything. I'm using web forms app, not MVC. Also, I'm new to ajax and their behavior. Thanks.
First, I assume that the url in you JQuery call is valid as there is not aspx extension their.
Second, It looks like what you need to do is create a web method and call it from JQuery for example the following is a web method that accept string
[WebMethod]
public static string GetData(String input)
{
return DateTime.Now.ToString();
}
and you can call it using the same way with your current code just update the url parameter to include the method name
url: "PageName.aspx/MethodName",
for more details about web methods and their union with JQuery please check this article
Edited The following is complete sample
The web method should look like the following one
[WebMethod]
public static string GetData(string filterValues)
{
return filterValues; //This should be updated to return whatever value you need
}
The client side part of calling the web method should look like the following
$.ajax({
url: "/Default/GetData",
type: "POST",
contentType: "application/json; charset=utf-8", //I have added this as "contentType" parameter represents the type of data inside the request meanwhile the "data" parameter describes the data inside the response
data: "{ filterValues:\"" + filterCheckboxes + "\"}", //Note that I have updated the string here also set the name of the parameter similar to the input of the webmethod
dataType: "json",
success: function (result) {
alert(result.d);//You should access the data using the ".d"
}
});
One last thing, If you are using asp.net permanent routing the above code will not work and you should disable it by updating the file "App_Code/RouteConfig.cs" From
settings.AutoRedirectMode = RedirectMode.Permanent;
To
settings.AutoRedirectMode = RedirectMode.Off;
And remember to clear browser cache after the above update

Searching in asp.net mvc4

I am newbie to asp.net MVC4.
For searching names from list i tried a search filter in MVC4.
This is controller-
public ActionResult SearchUser(string Email, int? UserId) {
var system = from u in db.SystemUsers
select u;
if (!String.IsNullOrEmpty(Email)) {
system = system.Where(c => c.Email.Contains(Email));
}
return View(system.Where(x=>x.Email==Email));
}
View-
<input type="text" id="search-User" />
<button id="text-email">search</button>
Ajax handling-
<script type="text/javascript">
$(document).ready(function () {
$('#text-email').click(function () {
var areavalue = $('#search-User').val();
alert(areavalue);
$.ajax({
url: '/Allusers/SearchUser/?Email=' + areavalue,
type: 'get',
datatype: 'json'
});
});
});
</script>
ViewModel-
public class UserModel
{
[Required]
public string Email { get; set; }
public int UserId { get; set; }
}
I have many users as a list, so i wanted to filter out any user from the list. For this I am using input element to get exact name as it is in list. Thus this name is passed to controller to find the exact match.
It is showing value i passed through ajax handling but not showing filtered result.
How can I perform searching in Asp.net MVC4?
I would use better Load() function for this porpose:
<script>
$(function () {
$('#text-email').click(function () {
var areavalue = $('#search-User').val();
$(".YourDivForResults").Load('/Allusers/SearchUser/?Email=' + areavalue)
});
});
</script>
And, as a recommendation, modify a bit your ActionResult as follows:
system = system.Where(c => c.Email.ToUpper().Trim().Contains(Email.ToUpper().Trim()));
This way you will avoid problems with empty spaces and Upper or Low letters.
Your ajax function is sending the data up to the server, but it is not doing anything with the result. In order to use the results, you should use the done promise method in the jQuery .ajax method that you are calling. It will look something like this:
$.ajax({
url: '/Allusers/SearchUser/?Email=' + areavalue,
type: 'get',
datatype: 'json'
}).done(
function(data, textStatus, jqXHR) {
var object = jQuery.parseJSON(data);
// LOGIC FOR UPDATING UI WITH RESULTS GOES HERE
}
);
You could alternatively use the Success callback option (instead of done). But the key is to provide logic for what to do with the data returned by the Action.
Also, if you are intending to return results using your ViewModel, you may need to return UserModel objects from your Linq query.
And if you are expecting JSON back from your action, you should not return View. Instead, try returnins JSON(data). (See here for more).
You need to make small change to you action like,
public ActionResult SearchUser(string Email, int? UserId) {
var system = from u in db.SystemUsers
select u;
if (!String.IsNullOrEmpty(Email)) {
system = system.Where(c => c.Email.Contains(Email));
}
return Json(system.Where(x=>x.Email==Email),JsonRequestBehavior.AllowGet);
}
and in your ajax call
$(document).ready(function () {
$('#text-email').click(function () {
var areavalue = $('#search-User').val();
alert(areavalue);
$.ajax({
url: '/Allusers/SearchUser/?Email=' + areavalue,
type: 'get',
datatype: 'json',
success:function(data){JSON.stringify(data);}
});
});
});
so that you will get the search result in a json format. you can make use of it. Hope it helps

Categories

Resources