I'm having troubles catching a response from Rails controller upon saving a model. I can see that the XHR response is generated in the Network tab of Chrome's devtools, but success or error functions don't fire. I suspect that this is a consequences of forcing post method and different url directly in the view, but I'm not sure, maybe I've messed up some syntax. Here's the snippet of the the save function in coffee:
save: (user_id) =>
model = #model
if $(".task").val()
#$el.find(".task").each ->
model.set
body: #value
user_id: user_id
task_title_id: model.id
return
model.save null, type: 'post', url: '/tasks',
success: (model, response) ->
console.log 'tasks saved!'
error: (model, response) ->
console.log "error! ", response.responseText
else
console.log 'nothing to save'
and compiled JS:
save = function(user_id) {
var model;
model = this.model;
if ($(".task").val()) {
this.$el.find(".task").each(function() {
model.set({
body: this.value,
user_id: user_id,
task_title_id: model.id
});
});
return model.save(null, {
type: 'post',
url: '/tasks'
}, {
success: function(model, response) {
return console.log('tasks saved!');
},
error: function(model, response) {
return console.log("error! ", response.responseText);
}
});
} else {
return console.log('nothing to save');
}
};
Trivia: I have to generate a new Task view for each existing TasktTitle and then submit these new Tasks to the server. Being very new to the Backbone I couldn't come up with a better idea other than render TaskTitles collection and add input field for each TaskTitle view and then force post method and /tasks url on save. It does feel quite dirty, but it works as expected with the exception of catching the response, which is a crucial part because there is more logic happens on success\error.
Related
I'm trying to make an ajax request to an MVC controller but I keep getting a 404 error whenever I try execute my script.
Failed to load resource: the server responded with a status of 404 ()
https://localhost:44301/LocationMapping/Test
My request just returns error get from the code snippet below.
The structure of the relevant files in my project are
View where request is called -> courselister/index.cshtml
View's Controller -> CourseListerController.cs
My Controller for handling Ajax requests from the above view-> LocationMappingController.cs
The reason I am handling the requests from a different controller is because several views will use the same requests and so it seems better to keep these all together in LocationMappingController.
Here is the code for my ajax request
$(document).ready(function () {
$.ajax({
url: "/LocationMapping/Test",
type: "GET",
dataType: "json",
data: {},
error: function (error) {
alert('error get');
},
success: function (data) {
alert('GET success');
alert(data);
}
});
});
Here is the code in the LocationMapping Controller
public JsonResult Test() {
{
return Json("Get Test", JsonRequestBehavior.AllowGet);
}
My current theory is that the server cannot find the route /LocationMapping/Test because it is not it the view's controller (CourseListerController.cs). It has taken a long time for me already to find a solution and so I am turning to the SO community to help.
Any help is appreciated.
Update: I tried creating a new controller and a view associated with it as follows,
TestAjaxController.cs
public ActionResult Index()
{
return View();
}
public JsonResult GetResponse(string str)
{
return Json(str, JsonRequestBehavior.AllowGet);
}
TestAjaxController/Index.cshtml
<div>
<h1>Test Ajax Page: Location Mapping</h1>
<button onclick="callAjax()">Click Me</button>
<script>
//document.ready(function () {
console.log('jquery loaded');
function callAjax() {
$(document).ready(function () {
alert("called");
jQuery.ajax({
url: "/TestAjax/GetResponse",
type: "GET",
dataType: "json",
data: { str: "this is the string I want to get as a response" },
error: function () {
alert("Error occurred calling GetResponse");
},
success: function (data) {
alert(data);
}
});
});
}
</script>
</div>
and this works! I get prompted with the "this is the string I want to get as a response". I don't understand why it works when my other controller will not..
Faced the same issue. Closed the localhost tab in browser and ran start without debugging. I was able to view the JSON data in the route.
I am building a .NET page for a project that adds a new City and State for a new user or updates the City and state if their ID is already in the database. Everything is working fine except for the fact that if a past user clicks submit to update their information, an entirely new entry is added to the database.
I have created the method already in the repository listed below.
public async Task<LocationViewModel> SaveLocationAsync(LocationViewModel model)
{
try
{
var location = new Location()
{
City = model.City,
State = model.State
};
if (model.Id != 0)
{
location.Id = model.Id;
}
_dbcontext.Location.AddOrUpdate(location);
await _dbcontext.SaveChangesAsync();
return model;
}
catch (Exception ex)
{
model.Error = true;
model.ErrorMessages = new List<string>()
{
string.Format("Something went wrong - Message: {0} \n Stack Trace: {1}", ex.Message,
ex.StackTrace)
};
return model;
}
}
I have also built a controller that saves and updates existing records asynchronously shown below.
[System.Web.Mvc.AllowAnonymous]
[System.Web.Http.HttpPost]
public async Task<LocationViewModel> SaveLocationApiAsync(LocationViewModel model)
{
var result = new LocationViewModel();
if (ModelState.IsValid)
{
result = await _locationRepository.SaveLocationAsync(model);
}
return result;
}
In addition, I have added added all of my routes and references.
Why is a new entry put in the database instead of the current one updating? The Javascript is shown below.
self.Submit = function () {
if (self.errors().length !== 0) {
self.errors.showAllMessages();
return;
}
if (isNumber(locationId)) {
self.Location().LocationId(locationId);
swal("Success", "Thank you for your submission \nYour information has been updated.", "success");
}
var newData = ko.mapping.toJSON(self.Location());
var url = "/Admin/SaveLocationApiAsync/Post/";
$.ajax({
url: url,
method: "POST",
data: newData,
contentType: 'application/json; charset=utf-8',
dataType: 'json',
success: function (result) {
if (result.Error === true) {
swal("Error", result.ErrorMessages.join('\n'), "error");
} else {
//TOdo
}
},
error: function () {
swal("Error", "Something went wrong.\nPlease contact help.", "error");
}
});
};
I apologize if it is a lot. I have checked everything repeatedly and have fixed all bugs. I am out of ideas.
Thanks in advance.
Your url looks to the controller action seems incorrect. You have var url = "/Admin/SaveLocationApiAsync/Post/"; when it should be var url = "/Admin/SaveLocationApiAsync";
Another approach to getting the correct url would be:
var url = '#Url.Action("SaveLocationApiAsync", "<ControllerName>")';
Also, in your ajax error handler you can get the HTTP status code and error message, which would help.
error: function (jqXHR, textStatus, errorThrown) {
swal("Error", "Something went wrong.\nPlease contact help.", "error");
}
EDIT:
I should have prefaced that using Url.Action works when your JavaScript is in a view (assuming Razor view in this case).
Fiddler is great tool to use when debugging ajax calls.
I have a project in MVC4 with C#. In this project, one of my controllers has a method to be called by an Ajax function:
[HttpPost]
public string EditPackage(int id, string newPkgName)
{
try{
//do logic here
return "OK";
}catch(Exception exc){
return "An error occurred, please try later! " + exc.Message;
}
}
This method is called by the following Ajax functions, using jQuery:
$.ajax({
url: $(this).data('url'),
type: 'POST',
contentType: 'application/json; charset=utf-8',
traditional: true,
data: JSON.stringify({ id: id, newPkgName: newPkgName}),
success: function () {
location.reload(true);
successNotification("Package edited successfuly!");
},
error: function (message) {
errorNotification(message);
}
});
The problem with this code, is that even if the server returns the return "An error occurred, please try later! " + exc.Message; message in the catch, the success function is the one always called.
In order words, I never run the error function no matter what I do.
To fix this I checked the official documentation:
http://api.jquery.com/jQuery.ajax/
However, since I am failry new to this I can't understand any of the parameters, nor how to use them effectively.
How can I create a good error message with all the possible information using Ajax, jQuery and my controller?
The error part of the $.ajax call only fires if the returned status code is anything other than 200 OK. In your case you are returning a plaintext response which will therefore be 200. You can change this behaviour like this:
try {
// do logic here
return "OK";
}
catch (Exception exc) {
return new HttpStatusCodeResult(HttpStatusCode.BadRequest, "Bad Request");
}
error: function (jqXHR, textStatus, errorThrown) {
errorNotification(textStatus);
}
You can change the HttpStatusCode to whatever suits your need.
Alternatively, you can keep the 200 response and return JSON with a flag to indicate whether or not the request was successful:
[HttpPost]
public ActionResult EditPackage(int id, string newPkgName)
{
try {
//do logic here
return Json(new { Success = true, Message = "OK"});
}
catch (Exception exc) {
return Json(new { Success = false, Message = "An error occurred, please try later! " + exc.Message });
}
}
Then you can remove the error handler, and check the state of the flag in your success handler:
success: function(response) {
if (response.Success) {
location.reload(true);
successNotification("Package edited successfuly!");
}
else {
errorNotification(response.Message);
}
},
I do the following, it might not be the best approach but it works for what I try to do.
[HttpPost]
public ActionResult EditPackage(int id, string newPkgName)
{
try{
//do logic here
return Json(new {Success = true, Message = "OK"});
}catch(Exception exc){
return Json(new {Success = false, Message = "An error occurred, please try later! " + exc.Message});
}
}
Then my Ajax looks as follows:
$.ajax({
url: $(this).data('url'),
type: 'POST',
contentType: 'application/json; charset=utf-8',
traditional: true,
data: JSON.stringify({ id: id, newPkgName: newPkgName}),
success: function (data) {
if(data.Success)
{
location.reload(true);
successNotification("Package edited successfuly!");
}
else
{
errorNotification(data.Message);
}
},
error: function (message) {
errorNotification(message);
}
});
I do this so that you have the standard error catching http errors from the server, but it means you can pass a success or failure back in a way that is more useful. It also means that if your update fails for a validation reason or something you can pass that message back nicely.
I got some problem while posting JSON data into MVC 4 controller.
Below method is working fine in Firefox but unfortunately failed in IE 9
The JavaScript :
var newCustomer = {
CustName: $("#CustName").val(),
CustLocalName: $("#CustLocalName").val(),
CustNumber: $("#CustNumber").val(),
CountryID: $("#SelectCountry").val(),
City: $("#City").val()
};
$.ajax({
url: '#Url.Content("~/CustomerHeader/CreateCustomerHeader")',
cache: false,
type: "POST",
dataType: "json",
contentType: 'application/json; charset=utf-8',
data: JSON.stringify(newCustomer),
success: function (mydata) {
$("#message").html("Success");
},
error: function () {
$("#message").html("Save failed");
}
});
and this is my controller :
public JsonResult CreateCustomerHeader(CustomerHeader record)
{
try
{
if (!ModelState.IsValid)
{
return Json(new { Result = "ERROR", Message = "Form is not valid! Please correct it and try again." });
}
RepositoryHeader.Update(record);
return Json(new { Result = "OK", Record = record});
}
catch (Exception ex)
{
return Json(new { Result = "ERROR", Message = ex.Message });
}
}
the "data" variable as in public JsonResult CreateCustomerHeader(CustomerHeader **data**) is getting NULL but while using FireFox it holds the correct value.
UPDATE : New method trying using $.post
function CreateNewCustomer(newCustomer) {
$.post("/CustomerHeader/CreateCustomerHeader",
newCustomer,
function (response, status, jqxhr) {
console.log(response.toString())
});
}
Based off the bit that you've shown, this is a simplified variation that may work more consistently, using jQuery.post() (http://api.jquery.com/jQuery.post/):
var data = {
CustName: $("#CustName").val(),
CustLocalName: $("#CustLocalName").val(),
CustNumber: $("#CustNumber").val(),
CountryID: $("#SelectCountry").val(),
City: $("#City").val()
};
$.post({
'#Url.Action("CreateCustomerHeader", "CustomerHeader")',
data,
function(response, status, jqxhr){
// do something with the response data
}).success(function () {
$("#message").html("Success");
}).error(function () {
$("#message").html("Save failed");
});
$.post() uses $.ajax as it's base, but abstracts some of the details away. For instance, $.post calls are not cached, so you don't need to set the cache state (and setting it is ignored if you do). Using a simple JavaScript object lets jQuery decide how to serialize the POST variables; when using this format, I rarely have issues with the model binder not being able to properly bind to my .NET classes.
response is whatever you send back from the controller; in your case, a JSON object. status is a simple text value like success or error, and jqxhr is a jQuery XMLHttpRequest object, which you could use to get some more information about the request, but I rarely find a need for it.
first of all I would like to apologize #Tieson.T for not providing details on JavaScript section of the view. The problem is actually caused by $('#addCustomerHeaderModal').modal('hide') that occurred just after ajax call.
The full script :
try{ ..
var newCustomer =
{
CustName: $("#CustName").val(),
CustLocalName: $("#CustLocalName").val(),
CustNumber: $("#CustNumber").val(),
CountryID: $("#SelectCountry").val(),
City: $("#City").val()
};
$.ajax({
url: '/CustomerHeader/CreateCustomerHeader',
cache: false,
type: "POST",
dataType: "json",
data: JSON.stringify(newCustomer),
contentType: "application/json; charset=utf-8",
success: function (mydata) {
$("#message").html("Success");
},
error: function () {
$("#message").html("Save failed");
}
});
}
catch(Error) {
console.log(Error.toString());
}
//$('#addCustomerHeaderModal').modal('hide')//THIS is the part that causing controller cannot retrieve the data but happened only with IE!
I have commented $('#addCustomerHeaderModal').modal('hide') and now the value received by controller is no more NULL with IE. Don't know why modal-hide event behave like this with IE9.
Thanks for all the efforts in solving my problem guys :-)
Is there a way to debug or get an error when wijdatasource complete is request with a wijhttpproxy and have some problems with the data?
data: new wijdatasource({
dynamic: true,
proxy: new wijhttpproxy({
url: "#Url.Action("List")",
type: "POST",
dataType: "json"
}),
reader: {
read: function (datasource) {
alert(datasource);
var count = datasource.data.TotalRowCount;
datasource.data = datasource.data.Items;
datasource.data.totalRows = count;
new wijarrayreader([
{ name: "CdCF", mapping: "CdCF" },
{ name: "Descrizione", mapping: "Descrizione" }
]).read(datasource);
}
}
})
With the internet explorer debugger I can see the call is made with a 200 HTTP response to the List action but "alert(datasource);" is never executed.
I want to get the error that make the datasource not parse the data (if this is the error).
In a standard ajax call I could have had an "error" callback to try to debug the problem.
$.ajax({
error: function (error) {
alert("error: " + error);
},
url: '#Url.Action("List")',
success: function (code) {
var myModel = {
items: eval(code)
};
}
});
I think you want to do a Get instead of a Post.
proxy: new wijhttpproxy({
url: "#Url.Action("List")",
type: "Get",
dataType: "json"
}),
What I did is that I caught the error in the controller an modified the object I was sending back to have a "success" boolean that I checked on the read function so that if datasource.data.success was true, then I would process the data if not I would spit out a message. You would have to put everything in your controller action inside a try-catch block.