I have created a view where when the user selects 2 of the dropdown lists values, an AJAX method is kicked off to populate an additional dropdown list's values
The callback triggers, however I cannot work with the response.
I am probably doing more than one thing wrong, so any help would be greatly appreciated. I am very new to Asp.Net core mvc
My Controller code (simplified - parameters are being used and are working):
public IActionResult GetCodes(string location, string xType)
{
return Json(new Dictionary<string, string> {
{ "","" },
{ "Option1","120" },
{ "Option2","123" }
});
}
My jquery script on the view:
var ddl1val = $("#Location :selected").val().toLowerCase();
var ddl2val = $("#xType:selected").val().toLowerCase();
$.ajax({
type: "GET",
url: "/Ppl/GetCodes",
dataType: 'json',
data: { location: ddl1val, xtype: ddl2val},
success: function (data) {
$("#ddlOptions").empty();
var ops = '<option value=""></option>';
alert(data); //returns [object Object]
alert(data.Key); //returns undefined???
//I need this to work
for (var i = 0; i < data.length; i++) {
ops += '<option value="' + data[i].Key + '">' + data[i].Value + '</option>';
$("#ddlOptions").html(ops);
}
}
console.log(data) shows:
{"": "", Option1: "120", Option2: "123"}
I am not restricted to use JSON return, but it is lighter than xml, so I would prefer using it
Serialising a Dictionary<> to JSON will result in an object like this in your JS:
{
"": "",
"Option1": "120",
"Option2": "123"
}
As such you should not use a for loop to enumerate it. As you're using jQuery you can use $.map() instead. Also note that you don't need to add the empty option as you include that in the response from the MVC endpoint. You also don't need to call empty() as you're overwriting the HTML of the select completely. Try this:
var data = {
"": "",
"Option1": "120",
"Option2": "123"
}
// inside the success callback:
var ops = $.map(data, function(v, k) {
return '<option value="' + v + '">' + k + '</option>';
});
$("#ddlOptions").html(ops);
<script src="https://cdnjs.cloudflare.com/ajax/libs/jquery/3.3.1/jquery.min.js"></script>
<select id="ddlOptions"></select>
Related
In my application I have a drop-down menu that lists various customers, and a second drop-down that will list the cities with which a given customer is associated. Selecting a customer should populate the second drop-down with the relevant list of locations. This happens by triggering an Ajax call to a method in the controller, which passes the name of the selected customer in variable "loc". The list of locations is obtained via an EF Core query.
This all works as expected on my local machine, but when running on our server it returns a 404 - Not Found error.
The Ajax call looks like this:
$.ajax({
url: "/[Controller]/GetLocations",
type: "POST",
dataType: "text",
data: { 'loc': loc },
success: function (data, textStatus, jqXHR) {
var listData = JSON.parse(data);
resetLocationList();
for (var listSize = 0; listSize < listData.length; listSize++) {
$('#ffBankLocation').append('<option value="' + listData[listSize] + '">' +
listData[listSize] + '</option>');
}
},
error: function (jqXHR, textStatus, errorThrown) {
console.log('Error caught: ');
console.log(errorThrown);
}
});
And the method in the controller looks like this:
[HttpPost]
public async Task<JsonResult> GetLocations(string loc)
{
var locations = await _repo.GetLocationsByName(loc);
return Json(locations);
}
Finally, the URL as reported in the 404 error looks like this:
https://[URL]/[Controller]/GetLocations?loc=Some%20Location
Given that the URL value isn't being found, I doubt the settings after that have anything to do with the problem. The only thing I could think to change there is that the controller was contained in a sub-folder within the Controllers folder (Controllers/myFolder/Controller), but moving the controller to the main Controllers folder, no sub-folder in between, doesn't resolve the issue.
Any advice appreciated.
EDIT: To be clear about moving the controller, I did not move it from the main Controllers folder, I only moved it out of the sub-directory within the Controllers folder in which it was previously found.
try to remove [HttpPost], and add attribute route
[Route("~/mycontroller/GetLocations")]
public async Task<JsonResult> GetLocations(string loc)
if it is still not working try to change ajax to get
$.ajax({
url: "/[Controller]/GetLocations?loc="+loc,
type: "GET",
dataType: "json",
success: function (data, textStatus, jqXHR) {
and never ever move controllers from default Controllers folder
Problem solved. I needed to convert my drop-down list into an #Html.DropDownListFor object, and wrap it in a form object like so:
<form id="custNameForm" asp-controller="myController" asp-action="GetLocations" method="post">
#Html.AntiForgeryToken()
#Html.DropDownListFor(x => x.Name, new SelectList((List<string>)ViewBag.custList), "Select Customer",
new { #class="form-control text-center" })
</form>
Next, in my javascript file, I add the following "change" listener:
.on('change', '#CustName', function (e) {
e.preventDefault();
GetLocations(e);
})
...which points to this jquery function:
function GetLocations(e) {
var loc = $('#CustName option:selected').val();
var noLoc = loc === '' || loc === 'Select Customer';
if (!noLoc) {
var form = $('#custNameForm');
var url = form.attr('action');
var token = $('input[name="__RequestVerificationToken"]').val();
$.ajax({
url: url,
type: "POST",
dataType: "json",
data: {
__RequestVerificationToken: token,
'loc': loc
},
success: function (data, textStatus, jqXHR) {
var listData = data;
resetLocationList();
for (var listSize = 0; listSize < listData.length; listSize++) {
$('#custLocation').append('<option value="' + listData[listSize] + '">' + listData[listSize] + '</option>');
}
},
error: function (jqXHR, textStatus, errorThrown) {
console.log('Error caught: ');
console.log(errorThrown);
}
});
}
else {
parseXML('');
}
$('#custLocation').prop('disabled', noLoc);
}
... where "#custLocation is the ID of the dropdown to be populated with the list of customer locations.
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);
}
}
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
}
}
};
I'm developing an online application of tennis club management... (MVC 3, Entity Framework Code first,...)
I've an Interface that allows the user to consult the available tennis court :
In my "AvailableCourtController", I've a function which return the tennis courts :
[HttpPost]
public JsonResult GetTennisCourt(DateTime date)
{
var reservations = db.Reservations.Include(c => c.Customer);
foreach (var reservation in reservations)
{
//Verify that a court is available or not
if (reservation.Date ==date)
{
if (date.Hour > reservation.FinishTime.Hour || date.Hour < reservation.StartTime.Hour)
{
var id = reservation.TennisCourtID;
TennisCourt tennisCourt = (TennisCourt) db.TennisCourts.Where(t => t.ID == id);
tennisCourt.Available = true;
db.Entry(tennisCourt).State = EntityState.Modified;
db.SaveChanges();
}
else
{
var id = reservation.TennisCourtID;
TennisCourt tennisCourt = (TennisCourt) db.TennisCourts.Where(s => s.ID == id);
tennisCourt.Available = false;
db.Entry(tennisCourt).State = EntityState.Modified;
db.SaveChanges();
break;
}
}
}
var courts = from c in db.TennisCourts
select c;
courts = courts.OrderBy(c => c.ID);
return Json(courts, JsonRequestBehavior.AllowGet );
}
So, I would like to change the color of my label if the tennis court is busy or free... For that I use "Ajax":
"View" (What I've tried to make)
<input id="datePicker" type= "text" onchange="loadCourts"/>
<script type="text/javascript">
$('#datePicker').datetimepicker();
</script>
<script type="text/javascript">
function loadCourts() {
var myDate = $('#datePicker').value();
$.ajax({
url: ("/AvailableCourt/GetTennisCourt?date=myDate "),
success: function (data) {
alert('test');
//change label's color
}
});
}
</script>
I never get the message "test"... So I have make something wrong with my Ajax function or my controller's method... My goal is to get the tennis court, check if they're free or not and change color in red if busy, and in green if free...
Can you help me to find what I'm doing wrong please? Sorry :( But I'm a beginner with Ajax...
This line is not passing a date in the querystring:
url: ("/AvailableCourt/GetTennisCourt?date=myDate "),
should be:
url: ("/AvailableCourt/GetTennisCourt?date=" + myDate),
EDIT: Also you're not getting the value correctly:
var myDate = $('#datePicker').value();
should be:
var myDate = $('#datePicker').val();
Your datetimepicker() call has to occur inside of a document.ready. Here is the corrected code:
<input id="datePicker" type= "text"/>
<script type="text/javascript">
$(document).ready(function () {
$('#datePicker').datetimepicker();
$('#datePicker').change(loadCourts);
});
function loadCourts() {
var myDate = $('#datePicker').val();
$.post({
data: "{ 'date' : " + myDate + " }",
url: (#Url.Action("AvailableCourt", "GetTennisCourt"),
success: function (data) {
alert('test');
//change label's color
}
});
}
</script>
}
Your url is wrong :-)
Should be:
$.ajax({
url: "/AvailableCourt/GetTennisCourt?date="+myDate, // without ( )
success: function (data) {
alert('test');
//change label's color
}
});
A more verbose AJAX call:
$.ajax({
type: 'POST',
data: "{ 'date' : " + myDate + " }",
url: '/AvailableCourt/GetTennisCourt',
contentType: 'application/json; charset=utf-8',
dataType: 'json',
timeout: 8000, // 8 second timeout
success: function (msg) {
},
error: function (x, t, m) {
if (t === "timeout") {
HandleTimeout();
} else {
alert(t);
}
}
});
I agree with #CAbbott that your URL was not created correctly. But with date values (and multiple query string values in general), you may be better off adding your date parameter in a data object literal in your ajax call:
function loadCourts() {
var myDate = $('#datePicker').val();
$.ajax({
url: ("/AvailableCourt/GetTennisCourt"),
data: { date: myDate },
success: function (data) {
alert('test');
//change label's color
}
});
}
jQuery will append your data onto the querystring for you and format it appropriately.
From the jQuery API docs:
The data option can contain either a query string of the form
key1=value1&key2=value2, or a map of the form {key1: 'value1', key2:
'value2'}. If the latter form is used, the data is converted into a
query string using jQuery.param() before it is sent.
I am having trouble passing my array via a $.post.
The Javascript
var privIDs = [1,2,4,5];
$.post("/Home/GrantPrivilegesToUser", { privilegeIDs: privIDs }, function (data) {
alert("Data Loaded: " + data.success);
});
The Action
public ActionResult GrantPrivilegesToUser(int[] privilegeIDs)
{
return Json(new {success=true});
}
The action sees privilegeIDs as null. Any ideas?
You need to set jQuery.ajaxSettings.traditional = true; for you jQuery ajax setting. In jQuery 1.4 they changed the way items are serialized in a form post.
please see:
http://forum.jquery.com/topic/nested-param-serialization
And:
How can I post an array of string to ASP.NET MVC Controller without a form?
I use JSON to pass data as a string using the JSON2 library: http://www.json.org/js.html
var privIDs = [1,2,3,4,5];
var data = JSON.stringify({privilegeIDs : privIDs});
$.POST("/Home/GrantPrivilegesToUser", data, function (data) {
alert("Data Loaded: " + data.success);
});
And the action would use the WebMethod type:
[WebMethod]
public object Entry_GetFormOptions(string privilegeIDs)
{
return new {success=true};
}
There are both built-in and 3rd party functions for parsing the received JSON to access the privilege IDs.
Let me know if this does or does not help.
This is what I ended up doing. Might be helpful to someone...
var privIDs = [1,2,4,5];
$.ajax({
type: "POST",
url: "/Home/UpdatePrivileges",
data: { privilegeIDs: privIDs },
traditional: true,
success: function (json) {
alert(json.success);
}
});
If you use .ajax instead of .post you can include traditional: true