I want to call a method from a controller to calculate a basic arithmetic operation. However, I get only undefined error. My code is
$("#equals3").click(
function () {
let display = $("#calculatorDisplay");
let currentValue = display.val();
$.ajax({
url:'Calculator/EvaluateExpressionAJAX',
type: 'POST',
data: { expression: currentValue },
contentType: 'application/json; charset=utf-8',
success: function (response) {
if (response.success) {
alert(response);
} else {
alert(response.responseText);
}
},
error: function (response) {
alert("error!");
}
});
});
My controller contains
public static Dictionary<string, ArithmeticOperation> EvaulationDictionary = new Dictionary<string, ArithmeticOperation> {
{ "+", (a, b) => a + b},
{ "-", (a, b) => a - b},
{ "*", (a, b) => a * b},
{ "/", (a, b) => a / b},
{ "%", (a, b) => a % b} };
[HttpPost]
public double EvaluateExpressionAJAX(string expression)
{
expression = expression.Trim();
string[] splitExpression = Regex.Split(expression, #"\s+");
double a = Convert.ToDouble(splitExpression[0]);
double b = Convert.ToDouble(splitExpression[2]);
string op = splitExpression[1];
return EvaulationDictionary[op](a, b);
}
Thanks in advance
If you would put a breakpoint in the javascript you'll probably find that MVC/WebApi returns an error page with a message like:
Invalid JSON primitive: expression
The JSON that you post is not valid, it isn't even JSON.
If you would replace that with:
data: "{ \"expression\": \"" + currentValue +"\" }",
That would post valid json to the ActionMethod.
A better option would be to create a JavaScript Object and stringify that, like this:
// create a js object before the Ajax call
let dataObj = { "expression": currentValue };
// change the data you send to this
data: JSON.stringify(dataObj),
And secondly: Take a good look at the url, I can't be sure, but if the page you rendered this from is the same controller and the index method, this probably won't work as you would expect. Change the URL to:
url:'/Calculator/EvaluateExpressionAJAX',
to make it absolute.
And finally, there are lot of possible bugs in the Action method. You can't expect users to supply 3 parts where part 1 and 3 are doubles. So there is a lot of checking missing.
And last but not least, if this is MVC, it is probably best to return ActionResult or some subtype, in this case JsonResult would suit best, from an actionmethod.
Related
I'm trying to code a simple autocomplete using LINQ to entities and Razor (new to c# sharp as well) and i'm having trouble displaying json data in my view.
My controller is as follows:
public ActionResult AutoCompleteCity(string guess)
{
List<City> listData = null;
if (!string.IsNullOrEmpty(guess))
{
listData = db.AutoCompleteCity(guess);
}
return Json(new { Data = listData });
}
AJAX call:
function getCities(input) {
var serviceURL = $("#autocompleteURL").val();
var url =
$.ajax({
type: "POST",
url: serviceURL,
data: {
'guess': input
},
dataType: 'json',
success: function (response) {
if (response.Data != null) {
if ($("#targetUL") != undefined) {
$("#targetUL").remove();
}
Data = response.Data;
$.each(Data, function (i, value) {
$("#targetUL").append($("<li class='targetLI' onclick='javascript:agregarTexto(this)'>" + JSON.stringify(value) + "</li>"));
});
});
}
I might be missing a bracket or two :D
Any way when i retrieve records from the database and try to pass JSON values to the view the output is:
{"Data":[{"Selected":false,"Text":null,"Value":null}]}
I assume I'm not passing the JSON listData correctly. Any input will be greatly appreciated, thanks!
EDIT: here is a screencap of the values returned by listData in my controller
This is my LINQ query
public List<City> AutoCompleteCity(string guess)
{
using (var context = new Sports.SportsEntities())
{
var query = (from loc in context.city
join prov in context.state on loc.STATE_ID equals prov.STATE_ID
where loc.CITY_DESC.Contains(guess.ToUpper())
select new
{
city = loc.CITY_DESC,
state = prov.STATE_DESC,
});
IEnumerable<City> cityList= from ba in query.AsEnumerable()
select new City(ba.city, ba.state);
return cityList.ToList();
}
}
This error:
{"Data":[{"Selected":false,"Text":null,"Value":null}]}
was caused by having declared private attributes in the City Class, or by failing to declare getter/setter methods if said attributes are meant to be private.
I figured that out by looking at the screen capture posted on my question, only displaying the "selected", "text" and "value" properties and not the city and state description in the query results, which was what I needed to display below the textbox input.
This controller method will do the trick:
public JsonResult AutoCompleteCity(string term)
{
List<City> listData = new List<City>();
if (!string.IsNullOrEmpty(term))
{
listData = db.AutoCompleteCity(term);
}
return Json(listData, JsonRequestBehavior.AllowGet);
}
The problem is probably this piece of code in the AJAX call:
if ($("#targetUL") != undefined) {
$("#targetUL").remove();
}
By doing this you are removing the ul tag from the DOM and therefore cannot add the li elements you are constructing in this piece of code:
$.each(Data, function (i, value) {
$("#targetUL").append($("<li class='targetLI' onclick='javascript:agregarTexto(this)'>" + JSON.stringify(value) + "</li>"));
});
If you want to clear the list use .empty():
if ($("#targetUL") != undefined) {
$("#targetUL").empty();
}
if you want to return a JSON, change that:
public ActionResult AutoCompleteCity(string guess)
by
public JsonResult AutoCompleteCity(string guess)
and also try that:
Data = JSON.parse(response.Data);
It looks like your method returns a list of City objects, so maybe you need to use the property of that objects to get to the city name, something like this:
$.each(Data, function (i, city) {
$("#targetUL").append($("<li class='targetLI' onclick='javascript:agregarTexto(this)'>" + city.Name + "</li>"));
});
Here's my controller action
[HttpGet]
public JsonResult GetOrderNum(String input)
{
AEntities db = new AEntities();
var result = from r in db.orders
where r.TrackingNumber.ToString() == input
select new {
r.Status,
};
return Json(result, JsonRequestBehavior.AllowGet);
}
And here I make the AJAX call
var myActionUrl = '#Url.Action("GetTrackingNumber", "ACustomer")';
var trackingInfo = $('#TrackingNumber').val();
$('.Track').click(function () {
$.ajax({
type: "GET",
url: myActionUrl,
data: $('#TrackingNumber').val(),
contentType: "application/json; charset=utf-8",
dataType: "json",
success: function (json) {
alert("Response as JS Object: " + json);
console.log(json);
}
});
the problem is that it wont read the r.TrackingNumber.ToString() as it is system.guid. Any idea how I can resolve this?
At the moment when I run it, I just get an empty array "[]".
There are a number of different ways that a GUID can be represented as a string.
System.Guid.ToString() provides an overload with a format specifier. Select a format specifier that matches the format of the GUID found in input.
UPDATE
'System.String ToString()' method, and this method cannot be translated into a store expression
You will need to instead create a GUID from input:
Guid inputGuid = Guid.Parse(input);
var result = from r in db.orders
where r.TrackingNumber == inputGuid
select new {
r.Status,
};
Change the method public JsonResult GetOrderNum(String input) to read public JsonResult GetOrderNum(Guid input) thus passing the parameter as a GUID. Then there is no need to convert the data store GUID.
function FunctionName(Input) {
$.ajax({
type: 'GET',
url: '/GetOrderNum?Input=' + Input=', // Your URL Here
data: $('#TrackingNumber').val(),
contentType: "application/json; charset=utf-8",
dataType: "json",
success: function (json) {
alert("Response as JS Object: " + json);
console.log(json);
}
});
}
[HttpGet]
public JsonResult GetOrderNum()
{
string input =HttpContext.Current.Request["Input"].ToString();
Guid input= Guid.Parse(input);
AEntities db = new AEntities();
var result = from r in db.orders
where r.TrackingNumber.ToString() == input
select new {
r.Status,
};
return Json(result, JsonRequestBehavior.AllowGet);
}
I've created a dictionary on cliend side and want to send it on sever side. In my script, dictionary is created correctly, but I'm not sure abount my ajax code.
$("#btnSubmit").click(function () {
var sendList = new Array();
var elems = $(".elemValue");
$.each(elems, function (key, value) {
if (value.attributes.elemName.nodeValue != "PhotoImg") {
sendList[value.attributes.elemName.nodeValue] = value.attributes.value.nodeValue;
}
});
var data = JSON.stringify({dict : sendList});
$.ajax({
type: "GET",
url: "dataloader.aspx/GetData",
data: data,
contentType: "application/json; charset=utf-8",
dataType: "json",
success: function (result){
alert(result.d);
}
});
});
On server side I wrote
[System.Web.Services.WebMethod]
public static string GetData(Dictionary<string,string> dict)
{
Dictionary<string, string> serverDict = new Dictionary<string, string>();
serverDict = dict;
string result = "";
foreach (var value in dict)
{
result += "The key is:" + value.Key + "The value is:" + value.Value;
}
return result;
}
Where are my mistakes, and how can I fix them? Help, please=)
I don't think it's possible to create a Dictionary from JSON. At least not without a lot of work. I would try changing it from a Dictionary to a List<KeyValuePair<string,string>> and see if it deserializes for you.
Reference for KeyValuePair
Once you've done that if you still need the Dictionary you can convert it fairly easily.
var Dictionary = new Dictionary<string,string>();
foreach(var KVP in List) Dictionary.Add(KVP.Key, KVP.Value);
Couple of things here:
You need to allow GET verb explicitly:
[System.Web.Services.WebMethod]
[System.Web.Script.Services.ScriptMethod(UseHttpGet=true)]
You are returning plain text from the server, which means that this line:
dataType: "json"
won't let jQuery parse the response correctly. You should either remove this line, or build response in JSON format.
I'm using $.post() to post an array of integer values to my controller.
Here's how I construct my array:
var ratings = [];
$('#ratings input[name=newReviewRatings]').each(function () {
ratings.push($(this).val());
});
Here's how I'm posting it to the controller:
$.post('#Url.Action("CreateReview", "Provider")',
{
id: providerId,
ratings: ratings,
comment: comment
});
Here's the form data that gets posted:
{id=437baf29-4196-4966-88de-a8fde87ef68d&ratings%5b%5d=1&ratings%5b%5d=2&ratings%5b%5d=3&ratings%5b%5d=4&ratings%5b%5d=5&comment=Comments}
And here's my controller signature:
public ActionResult CreateReview(Guid id, int[] ratings, string comment)
{
// ....
}
That seems like that should be right, but ratings is always null. Can anyone see what I'm missing?
I also tried string[] ratings and got the same result. I also saw a suggestion to pass the array using JSON.stringify(ratings) but that didn't seem to help either.
In adition to converting the post data to json, you can also set the traditional param to true. This will cause jQuery to use the correct post format for MVC.
jQuery.ajaxSettings.traditional = true;
$.post('#Url.Action("CreateReview", "Home")',
{
id: 'GUID STRING HERE',
ratings: [1, 2, 3],
comment: 'adfef'
});
Try to specify contentType like this:
$.ajax({
url:url,
type:"POST",
data:data,
contentType:"application/json; charset=utf-8",
dataType:"json",
success: function(){
...
}
})
UPDATE: This code now works! Between the answer below and my dev who emailed me from Romania, I got it sorted out.
[Method]
public object ConvDetails(string SENDERNAME, string VIEWURL)
{
{
var list = new List<object>();
new Command("select top 1 o.name [SENDERNAME], view_url [VIEWURL] from MESSAGE m join OPR_SECD o on UPDATED_BY = O.RECNUM where VIEW_URL like 'conversation.aspx%' and DELIVER_TO in (select OPR_INITIAL from OPR_SECD where recnum = #CURRENT_USER_ID) order by m.RECNUM desc")
.AddInt("CURRENT_USER_ID", Common.UserID)
.Each(R => list.Add(new
{
VIEWURL = R.GetString("VIEWURL"),
SENDERNAME = R.GetString("SENDERNAME")
}));
return list;
};
}
Here's my ajax call to get the two strings from my method:
convDetails: function() {
$.ajax({
url: BASE_URL + "pages/services/messages.ashx?method=convdetails",
dataType: "json",
async: true,
data: {},
success: function(data) {
$("a.new-message-alert").attr("href", '' + data[0].VIEWURL);
$("span#message-from").text("New Message From: " + data[0].SENDERNAME);
}
});
}
UPDATE:
Between the response I got below and a few emails to our developer who's in Romania, I was able to piece it together. I updated my code to what worked! The having just data.VIEWURL didn't work. I had to add the data[0].VIEWURL. So, thanks Matt for that one. Also, in my href i had to put in empty quotes or it would return NaN. No idea why.
Thanks!
Well, that JavaScript isn't going to work whatever you do on the C# side. You're attempting synchronous processing of the result of an asynchronous call.
Your C# doesn't look far off, for some reason I totally failed to read it correctly first time around. I've never used a .ashx in quite that manner, I've always just spat out my response from ProcessRequest, but if your code is getting called then I just learned something new. I do, however, notice that you're returning a serialized list, but only processing one element.
You could use a more LINQy approach to eliminate the explicit list filling, though:
var list =
from R in new Command("select top 1 o.name [SENDERNAME], view_url [VIEWURL] from MESSAGE m join OPR_SECD o on UPDATED_BY = O.RECNUM where VIEW_URL like 'conversation.aspx%' and DELIVER_TO in (select OPR_INITIAL from OPR_SECD where recnum = #CURRENT_USER_ID) order by m.RECNUM desc")
.AddInt("CURRENT_USER_ID", Common.UserID)
select new {
VIEWURL = R.GetString("VIEWURL"),
SENDERNAME = R.GetString("SENDERNAME") };
context.Response.Write(JsonConverter.SeralizeObject(list));
Your JS should look more like:
convDetails: function() {
$.ajax({
url: BASE_URL + "pages/services/messages.ashx?method=convdetails",
async: true,
data: {},
success: function(data) {
$("a.new-message-alert").attr("href", data[0].VIEWURL);
$("a.new-message-alert").text("New message from: " + data[0].SENDERNAME);
}
});
}