AJAX Call to MVC5 ActionResult - javascript

I am trying to figure out what is wrong with the following code:
$(".ReportScore").click(function () {
$.ajax({
type: "GET",
url: "/events/Tournaments/ReportScore",
success: function() {
location.reload();
},
error: function() {
alert("The scores were not recorded");
}
});
});
When I type the url in the bar, it works without problems, however when I try to do an ajax call I get 404 Page not found error.
To clarify, when I click on the button I Get a popup saying "The scores were not recorded" and on developer tools I get a script error saying Page not found.
I also have a breakpoint in visusal studio on the method itself, but the point is never hit as the method is never called.
Server Side Code:
public async Task<ActionResult> ReportScore()
{
var a = "abc"
}
var a line is never hit.
EDIT:
I have another ajax call from the same script that works without problems:
$("#InvitedMember").autocomplete({
source: function (request, response) {
$.ajax({
type: "POST",
url: "/events/Teams/Members",
data: { id: $("#InvitedMember").val() },
success: function (data) {
response($.map(data, function (item) {
return {
label: item.CustomUrl, value: item.CustomUrl
};
}));
}
});
},
create: function () {
$(this).data('ui-autocomplete')._renderItem = function (ul, item) {
return $('<li>')
.append("<a><div>" + item.label + "</div></a>")
.appendTo(ul);
};
},
select: function (event, ui) {
//you can access ui.item to get the selected item object.
$("#InvitedMember").val(ui.item.value);
return false;
}
});

It is not a good idea to hardcode your url's like that. You should always use the Url.Action or Url.RouteUrl html helper methods to build the relative url to the action methods/endpoints you are accessing. These helper methods will take care of correctly building the url regardless of your current page/path.
Also, from your comment,it seems like events is the name of your virtual directory/application name in your IIS. You should not use those in your code to build the urls as it might change based on your deployment. What if you want a a copy of your code deployed to "http://staging.yourSite.com" ?
As long as you use the Url.Action helper method,it will build the correct relative url to your app and you do not need to worry about your IIS virutal directory/application name.
var url = "#Url.Action("ReportScore","Tournaments")";
$.ajax({
type: "GET",
url:url,
success: function (res) {
alert('success happened');
//location.reload();
},
error: function () {
alert("The scores were not recorded");
}
});
The above code will work if you have it in a razor view. But if your ajax call code is in external js file, You may build the relative url to the app root and pass that to your js file and use that to build the url. You can use the #Url.Content("~") to build the url to app root. If you want, you can build the url to specific action method itself.
<script>
var myApp = myApp || {};
myApp.Urls = myApp.Urls || {};
myApp.Urls.baseUrl = '#Url.Content("~")';
myApp.Urls.reportScoreUrl= '#Url.Action("ReportScore","Tournaments")';
</script>
<script src="~/Scripts/PageSpecificExternalJsFile.js"></script>
And in your PageSpecificExternalJsFile.js file, you can read it like
var myUrlToUser = myApp.Urls.reportScoreUrl;
alert(myUrlToUser);
or build using the base url.
var myUrlToUser= myApp.Urls.baseUrl+"Tournaments/ReportScore";
alert(myUrlToUser);

The problem seems not in your javascript code but your controller action method (if it is indeed how it is written)
public async Task<ActionResult> ReportScore()
{
var a = "abc"
}
Your code block doesn't show any return statement, make sure your return value is awaited.
i.e.
return await "abc"

Related

How To Open URL In New Tab Using Ajax Success?

Here i am trying to open the file in new tab by calling ViewFile action of Doctor controller using Ajax Success which is in functionabc(this) on click of anchor tag.
Now the problem is that everything is as required but the url doesnot open in new tab.
Below is my Ajax
<script>
function abc(thisEvent) {
debugger;
var getDoCredId = $(thisEvent).attr('docCredId');
var parameter = { id: getDoCredId };
$.ajax({
url: "/Doctor/ViewFile1",
type: "get",
dataType: "html",
data: parameter,
success: function (data) {
debugger;
if (data = true) {
debugger;
var getdoctorId = $(thisEvent).attr('docCredId');
var url = "/Doctor/ViewFile/" + getdoctorId;
window.open(url, "_blank");
}
else {
debugger;
showNotification("Error", "warning");
}
}
});
}
Below is my anchor tag HTML
<a title="View Attachment" docCredId = "' + getDocCredId + '" onclick="abc(this)"><i class="btn btn-web-tbl btn-warning fa fa-eye "></i></a>
Below is code behind
public bool ViewFile1(int id)
{
var document = _doctorService.GetDoctorCredentialDetails(id);
string AttachPath = ConfigPath.DoctorCredentialsAttachmentPath;
string strFileFullPath = Path.Combine(AttachPath, document.AttachedFile);
string contentType = MimeTypes.GetMimeType(strFileFullPath);
bool checkFileInFolder = System.IO.File.Exists(strFileFullPath);
if (checkFileInFolder == true)
{
return true;
}
else
{
return false;
}
}
public ActionResult ViewFile(int id)
{
var document = _doctorService.GetDoctorCredentialDetails(id);
string AttachPath = ConfigPath.DoctorCredentialsAttachmentPath;
string strFileFullPath = Path.Combine(AttachPath, document.AttachedFile);
string contentType = MimeTypes.GetMimeType(strFileFullPath);
bool checkFileInFolder = System.IO.File.Exists(strFileFullPath);
bool filedata = System.IO.File.ReadAllBytes(strFileFullPath).Any();
byte[] filedata1 = System.IO.File.ReadAllBytes(strFileFullPath);
var cd = new System.Net.Mime.ContentDisposition
{
FileName = document.FileName,
Inline = true
};
Request.HttpContext.Response.Headers.Add("Content-Disposition", cd.ToString());
return File(filedata1, contentType);
}
Since this is too long for a regular comment, I am posting this as an answer, although it isn't directly going solve the problem because I am not able to reproduce it, but might give some insights and let you check the differences with what happens in your code as compared with this simplified example.
Calling window.open() from jQuery ajax success callback works just fine: https://codepen.io/nomaed/pen/dgezRa
I used the same pattern as you did, without your server code but using jsonplaceholder.typicode.com sample API instead.
There are some issues with the code sample that you might want to consider, even though you didn't ask for comments about it and it's not directly related to your issue (probably):
if (data = true) means data will always be true. You probably mean to do a if (data === true) if you know it's a boolean value, or if (data) if you want to accept any truthy value (true, {}, "something", 42, etc). Judging by the Java code and how you define the response format in the jQuery ajax call, it looks like you're expecting the "data" variable result be an HTML and not a boolean. You might want to try and remove the dataType: "html" row and let jQuery set the data format according to what is coming back from the server, and/or send a JSON formatted response, as in a POJO of { result: true } for a successful response. Then make sure that data.result === true to be sure that you got what you expect.
You should probably add arbitrary data to tags DOM elements the data-* attributes and if you're using jQuery, access them using the .data() selector. White adding just random attributs with string values may work, it's considered an abuse of the HTML and DOM, and the data-* attributes are there specifically for adding any data.
In the abc() function you grab the value of the attribute in the beginning (var getDoCredId = $(thisEvent).attr('docCredId');) but in the callback you're trying to get the value once more. You really don't need it since the success() callback is a closure in the scope of the abc() function and it has access to the value already, so doing var getdoctorId = $(thisEvent).attr('docCredId'); in the callback is really not needed.
I'd also suggest naming getDoCredId variable just as docCredId. Having a "get" prefix usually means that it's a getter function or a reference to some getter. Likewise, the "thisEvent" argument of the main function should probably be called "callerElement" or something like that since it's not an event, it's an actual element that you're passing directly from the DOM when calling abc(this) in the onClick event handler of the <a> anchor. This is just to make the code clearer to understand for anyone who's reading it, and for yourself when you're coming back to it several months in the future and trying to figure out what's going on :)
Try adding async: false to your Ajax request
function abc(thisEvent) {
debugger;
var getDoCredId = $(thisEvent).attr('docCredId');
var parameter = { id: getDoCredId };
$.ajax({
async: false, // <<<----------- add this
url: "/Doctor/ViewFile1",
type: "get",
dataType: "html",
data: parameter,
success: function (data) {
debugger;
if (data = true) {
debugger;
var getdoctorId = $(thisEvent).attr('docCredId');
var url = "/Doctor/ViewFile/" + getdoctorId;
window.open(url, "_blank");
}
else {
debugger;
showNotification("Error", "warning");
}
}
});
}

Ajax call not reaching controller method

Yes, there are a whole bunch of posts with similar questions. I've tried to follow the answers in them, but my ajax call still isn't reaching the controller method.
controller (SalesController.cs):
[HttpGet]
public JsonResult fillVarietiesSelect(int species_id)
{
String[] alist = {"a","b","c"};
return Json(alist, JsonRequestBehavior.AllowGet);
}
javascript:
$('#species-select').on('change', function () {
var species_id = $('#species-select').val();
console.log("species id selected " + species_id);
alert("species id selected " + species_id);
$('#variety-select').empty();
$.ajax({
type: 'GET',
url: '#Url.Action("fillVarietiesSelect", "Sales")',
data: {species_id : species_id},
success: function (result) {
alert(result);
}
});
});
The on change event is firing, and the alert pops up with the correct data. I have a breakpoint set at the controller method, but execution doesn't seem to get there.
try doing exactly like following
Controller:
[HttpGet]
public ActionResult receive2(string p)
{
ViewBag.name = p;
List<string> lst = new List<string>() { p };
return Json(lst,JsonRequestBehavior.AllowGet);
}
Client side
$.ajax({
type: "GET",
url: "Main/receive2", // the method we are calling
contentType: "application/json; charset=utf-8",
data: { "p": $("#txtname").val() },
dataType:"json",
success: function (result) {
alert("yes");
alert('Yay! It worked!tim' + result);
window.location = "http://google.com";
// Or if you are returning something
},
error: function (result) {
alert('Oh no aa :(' + result[0]);
}
});
I have checked it's working
I had the same issue, changing the parameter from int to string resolved the problem.
On the server side I had,
public string RemoveByDocumentID(int DocumentID)
changing that to
public string RemoveByDocumentID(string DocumentID)
resolved the issue.
On the same context, I have another method in the same name (overloaded method). Which was also contributing to the issue, so I made the method name unique.
Your 404 error is telling you that #Url.Action is not being parsed by the view engine. The # is Razor syntax, so for this to work you need to be using a .cshtml extension for C# views or .vbhtml for VB views and be using MVC 3 or above.

Extend a function stored in a variable

I have a large JavaScript project that makes several Ajax web service calls. The code to handle the web service calls comes from a shared external file.
To separate the web service from calling code, there is a global object to reference to the calling function like so
var doRemote ={};
$(document).ready(function(){
doRemote =getRemoteEndpoint('https://someplace.org/MyWebService.aspx');
}
A simplified version of the getRemoteEndpoint, which is in a file shared by several other pages in addition to the one I'm working on is as follows:
function getRemoteEndpoint(url) {
return function(methodName, options) {
var extension = {
url: url + '/' + methodName,
data: {},
async: true
};
var combined = $.extend({}, extension, options);
combined.data = JSON.stringify(combined.data);
return $.ajax( combined );
};
}
I invoke the web service calls by the following code
doRemote('WebServiceMethodName',
{
success: function(data) {
alert('Web Service Returned' + data);
},
error: function(req, stat, err) {
alert('Error');
}
});
I have the need to execute a function before executing the getRemoteEndpoint call in only the page I'm working on. Instead of calling the function before each of the 30 web service calls, I'd like to add a line of code to the function. I've tried to replace the doRemote assignment with the following.
doRemote =function() {
DoTask();
return getRemoteEndpoint('https://someplace.org/MyWebService.aspx');
};
DoTask is a named function in the program I'm working on. While it throws no errors, none of the Ajax calls work.
I tried to use the JQuery.extend function, but it didn't work either.
What am I doing wrong?
You have to actually call it to assign the result of getRemoteEndpoint to doRemote:
doRemote = (function() {
DoTask();
return getRemoteEndpoint('https://someplace.org/MyWebService.aspx');
})();
Update:
doRemote = (function() {
var oldDoRemote = getRemoteEndpoint('https://someplace.org/MyWebService.aspx');
return function(a1, a2) {
DoTask();
oldDoRemote(a1, a2);
}
})();

AJAX call using IIFE? Can't seem to get .done to work the same as a regular function

I currently have an AJAX call out to a PHP file that works, that is the following:
//Load map from database
function getMap(){
return $.ajax({
url: "getMap.php",
type: "POST",
dataType: 'JSON',
});
};
getMap().done(function(r) {
if (r) {
loadedMap(JSON.parse(r.mapArray), JSON.parse(r.mapProperties)); //call loadedMap(r) if loading a map from DB
} else {
console.log("No data");
}
}).fail(function(x) {
console.log("error");
});
That works within a single javascript file that successfully passes r.mapArray and r.mapProperties to my main loadedMap function.
I'm trying to learn about the IIFE Javascript Module model, and split my work up into separate files.
So, I currently have main.js:
(function() {
// let's get our map
var gameMap = mapGen.getMap().done();
console.log(gameMap);
})();
and mapGen.js:
var mapGen = function() {
return {
getMap: function() {
return $.ajax({
url: "getMap.php",
type: "POST",
dataType: 'JSON',
});
}
};
}()
If I console.log(gameMap), I see the responseText JSON object with my data. I just can't seem to access it. console.log(gameMap.responseText) is undefined. as is gameMap.responseJSON (though I see both of them in the console).
Looking the code over it looks as the the separation of the files was not the issue and that looks to be implemented correctly. The issue is with how you are handling the AJAX request. The function mapGen.getMap() actually returns a jqXHR Object as opposed to the response that you are trying to access.
Just as you had in your previous file, you will need handle the response of your request.
(function() {
// let's get our map request
var gameMap = mapGen.getMap();
gameMap.done(function(r){ ... }).
fail(function(x){ ... });
})();
You will be able to access the response data you are looking for within the done() function.

Setting string in javascript function in ASP.NET MVC give NullReferenceException

Inside my MVC view I have javascript that is executed by a button click. I'm trying to set a string to a random set of characters which I can get to work fine but when I try and set that string to 'randomchars' string inside the javascript I get a NullReferenceException when I try and run the view.
Below is the code snippet, the CreateRString is where the model parameter (RString) is set to the random string.
<script type="text/javascript">
function showAndroidToast(toast) {
var url = '#Url.Action("CreateRString", "Functions")';
$.ajax({ url: url, success: function (response) { window.location.href = response.Url; }, type: 'POST', dataType: 'json' });
var randomchars = '#(Model.RString)';
}
</script>
Is the syntax correct? I'm not too sure why it's getting the NULL.
The javascript is executed after the page been delivered to the client (i.e. web browser). Your razor code here is executed on the server before the page is sent to the client. Therefore, the ajax method will execute after you try to access Model.RString
To fix this you can either call CreateRString on the server, or you can set randomchars by using the response in the success callback.
To explain option 2 a bit further. You could do something like this:
//Action Method that returns data which includes your random chars
public JsonResult CreateRString()
{
var myRandomChars = "ABCDEF";
return new JsonResult() { Data = new { RandomChars = myRandomChars } };
}
//The ajax request will receive json created in the CreateRString method which
//contains the RandomChars
$.ajax({ url: url, success: function (response) {
var randomchars = response.Data.RandomChars;
window.location.href = response.Url;
}, type: 'POST', dataType: 'json' });
More specifically, the razor calls #Url.Action("CreateRString", "Functions") and #(Model.RString) execute first on the server.
Then showAndroidToast executes in the client's browser when you call it.

Categories