A controller returns an ActionResult, i.e.:
public async Task<ActionResult> Delete(int? id)
{
if (id == null)
{
return new HttpStatusCodeResult(HttpStatusCode.BadRequest);
}
// do something
return RedirectToAction("Index", "Orders", null });
}
this works fine is I use an ActionLink in the view.
But the actual call is done via Ajax:
$.ajax({
url: "/Orders/Delete",
cache: false,
data: { id: $("#btnCancel").data("id") }
}).done(function (response) {
$("html").html(response);
});
with the:
$("html").html(response);
line I'm trying to follow the returned html page.
It doesn't work: the html is rendered wrong (layout and colors are different) and even the address is not correct (of course it remains on the current page, instead to follow the Controller path).
I'm not sure if this is possible to do in jQuery.
Why I use an Ajax call instead of the ActionLink? Because I need to wait a confirm by the user:
$("#btnCancel").click(function () {
event.preventDefault();
swal({
title: "#Resources.MsgCancelOrderTitle",
text: "#Resources.MsgCancelOrderText",
type: "warning",
showCancelButton: true,
confirmButtonClass: "btn-danger",
confirmButtonText: "#Resources.MsgCancelOrderConfirm",
cancelButtonText: "#Resources.MsgCancelOrderCancel",
closeOnConfirm: false,
closeOnCancel: true
},
function (isConfirm) {
if (isConfirm) {
swal({
title: "#Resources.MsgCancelOrderSuccessTitle",
text: "#Resources.MsgCancelOrderSuccessText",
type: "success"
},
function () {
$.ajax({
url: "/Orders/Delete",
cache: false,
data: { id: $("#btnCancel").data("id") }
}).done(function (response) {
$("html").html(response);
});
});
}
});
});
If you want to redirect to another view, then don't bother with ajax, it defeats the entire purpose of it. Generally an ajax call returns either some data (JSON or XML) or a small snippet of HTML which is designed to fit somewhere within the page which made the ajax call (generally implemented in MVC as a Partial View).
If you need the redirect, then do it like this:
Once the user confirms their choice via the alert box, then if the request needed uses the GET method (like your example) then simply a call to window.location.href with the appropriate URL will do it. If it was using POST, then normally there'd be a HTML form you could instruct to submit itself.
Related
I have tried ways to search for a solution but I can't seem to find the right combination of words or something... here goes:
I have an ASP.NET MVC application that users scan inventory/package barcodes into. Every time someone scans an item, I make an async request and then display a popup message with information about the package. This part works as expected and does not block the application during the request:
$.ajax({
type: 'GET',
dataType: 'json',
async: false,
url: '#Url.Action("SingleOrderLookup")?trackingNumber=' + trackingId,
success: function (result) {
if (result.success) {
var audio = findAudio(result.model, audioClips, saturdayAudio);
suppressDefaultSound = true;
var titleText = result.model.displayPromptText;
if (result.model.isRefrigerated) {
isRefrigerated = true;
titleText = "<p style='color: blue;'>(REFRIGERATED)</p>" + "<p>" + result.model.displayPromptText + "</p>";
}
swal.fire({
title: titleText,
text: "Place in route for " + result.model.displayPromptText,
type: "success",
showCancelButton: false,
confirmButtonText: "Sorted",
cancelButtonText: "Cancel",
timer: 1750,
preConfirm: function () {
return new Promise(function (resolve) {
resolve();
}, 1000);
}
}).then(result => {
if (result.value) {
}
});
var dupe = findOrderByTrackingNumber(trkNumbers, result.model.trackingId);
if (!dupe) {
trkNumbers.push({ trackingNumber: trackingId, depotId: result.model.destinationHub });
pkgCount++;
if ($("#divUpdatePickup").is(":hidden"))
$("#divUpdatePickup").show();
AddLogToTable(trackingId);
} else {
//audible feedback that duplicate was scanned
//if (!trkBin) PlayAudio(2);
//PlayAudio(2);
}
//playing audio
if (isRefrigerated) {
setTimeout(function () {
if (audio) playByteArray(audio);
}, 1500);
PlayRefrigerate();
} else {
if (audio) playByteArray(audio);
}
}
if (result.nullRoute) {
addToTrkNumbers = false;
Swal.fire({
title: "NO ROUTE DEFINED",
text: "Unable to match order to a route!",
type: "warning",
showCancelButton: false
});
}
}
});
However, I want the page to make another async call to populate a variable with an array of objects, transparently and without blocking the user from making scans and receiving information back from the async calls from the above code. This call should occur immediately when the page is loaded, and it could take more than a minute or two to receive all the data expected from this call. Once the response is back, the collection variable (zipSort[]) should be populated. The data in this variable will contain a "cache" of elements that the page can query against to avoid having to make individual server-side calls after each scan (in essence, I want to "front-load" data needed for the scan events and once completed, individual calls to the server should not be necessary since this variable should contain 99% of the IDs expected to be scanned).
This is where I'm having an issue and it's probably due to a lack of understanding of how async calls/JS promises work. Here is the code I have so far for this:
//array to hold data on expected tracking number scans
var zipSort = []
async function getCheckinGroup(zipSort) {
console.log("Fetching complete check-in group...");
var url = '/SortFacility/HubManager/GetOrders';
var promise = new Promise((resolve,reject) => {
$.ajax({
type: "GET",
url: url,
cache: false,
async: true,
contentType: "application/json",
success: function (result) {
if (result.success) {
console.log("Retrieval success");
try {
zipSort = result.model;
resolve(result.model);
} catch (ex) {
reject("Some error?");
}
} else {
reject("Some error?");
}
},
error: function (ob, errStr) {
reject("Something went wrong");
}
});
});
return promise;
}
//don't want this to hold up execution of the rest of the code, so zipSort[] should
//remain empty and get set transparently when the ajax response is returned:
getCheckinGroup(zipSort);
Every version of code I'm trying out from articles and tutorials I have read holds up the UI and keeps users from being able to scan items while the response hasn't been returned. What am I missing? How should I change this so that (a) users can begin scanning immediately once the page has loaded and receive information from individual async calls to the DB, and (b) zipSort[] can be populated with the totality of any data potentially needed for these scans, and once populated, scan events trigger a lookup on that variable instead of continued individual calls to the database?
Any help would be appreciated!
Edit: tried simply adding this call in-line and no matter where I put it, it blocks the other code from running until response is received, even though async is set to true:
$.ajax({
type: "GET",
url: url,
cache: false,
async: true,
contentType: "application/json",
success: function (result) {
console.log("Data received.");
zipSort = result.model;
}
});
Thanks everyone for your help. I found this little gem, which solved my problem:
https://josef.codes/c-sharp-mvc-concurrent-ajax-calls-blocks-server/
Applying [SessionState(System.Web.SessionState.SessionStateBehavior.Disabled)] to my controller class enabled concurrent async ajax calls.
I'm using jquery DataTables to show some tabular data, and I also placed an edit link for each row in said jquery DataTables so that the user can edit data associated with a particular row if needed. ( Also, I have No clue how to use ASP.NET MVC Html helpers within jQuery DataTables so that is why I am using the html link in the following code )
jquery DataTable javascript:
$("#resultCodeTable").dataTable({
"processing": true,
"serverSide": false,
"destroy": shouldDestroy,
"ajax": {
"url": "../Admin/LoadResultCodes",
"type": "GET",
"datatype": "json",
"data": function (data) {
data.actionCodeIDArg = actionCodeIDInQuestion;
}
},
....................................
............................
..............
columnDefs: [
{
{
targets: 1,
searchable: false,
orderable: false,
name: "EditResultCodeInQuestionReasonForArrears",
"data": "ID",
render: function (data, type, full, meta) {
if (type === 'display') {
data = '<a class="editResultCodeInQuestionReasonForArrears" href="javascript:void(0)" data-id="' + full.ID + '">Edit RFAs</a>'
}
return data;
}
},
....................................
............................
..............
Clicking on the aforementioned link will ensure that the point of execution reaches the following jQuery Event Handler method:
jQuery Event handler method/ function Javascript
$('#resultCodeTable').on('click', '.editResultCodeInQuestionReasonForArrears', function () {
console.log(this.value);
navigateToAParticularResultCodeAssociatedReasonForArrearsList($(this).data('id'));
});
The jQuery Ajax call successfully invokes the C# Controller's action because I see the Visual Studio's Debugger's point of execution reach said Controller's action, however, it fail to navigate to the view that I want to show.
jquery / javascript:
function navigateToAParticularResultCodeAssociatedReasonForArrearsList(resultCodeTable_ID) {
console.log(resultCodeTable_ID);
$.ajax({
url: '../Admin/NavigateToAParticularResultCodeAssociatedReasonForArrearsList',
type: 'POST',
dataType: 'json',
contentType: "application/json;charset=utf-8",
data: "{'" + "resultCodeTable_IDArg':'" + resultCodeTable_ID + "'}",
cache: false,
}).done(function (response, status, jqxhr) {
})
.fail(function (jqxhr, status, error) {
// this is the ""error"" callback
});
}
C#: ( in my AdminController.cs )
public ActionResult NavigateToAParticularResultCodeAssociatedReasonForArrearsList(int resultCodeTable_IDArg)
{
AParticularResultCodeAssociatedReasonForArrearsListViewModel aParticularResultCodeAssociatedReasonForArrearsListViewModel = new AParticularResultCodeAssociatedReasonForArrearsListViewModel();
aParticularResultCodeAssociatedReasonForArrearsListViewModel.ResultCodeTable_ID = resultCodeTable_IDArg;
return View("~/Areas/Admin/Views/Admin/AdminModules/Auxiliaries/AParticularResultCodeAssociatedReasonForArrearsList.cshtml", aParticularResultCodeAssociatedReasonForArrearsListViewModel);
}
Razor / Html: (In my \Areas\Admin\Views\Admin\AdminModules\Auxiliaries\AParticularResultCodeAssociatedReasonForArrearsList.cshtml view )
#model Trilogy.Areas.Admin.ViewModels.Auxiliaries.AParticularResultCodeAssociatedReasonForArrearsListViewModel
#{
ViewBag.Title = "AParticularResultCodeAssociatedReasonForArrearsList";
}
<h2>AParticularResultCodeAssociatedReasonForArrearsList</h2>
Could someone please tell me how I can change the code so that the view shows up after the jquery Ajax invocation?
May be on .done function you will get the view in the response, you need to take that response and bind it to your control
You call the controller via AJAX, and sure it hits the controller action method, and the controller returns a view but this is your code that deals with whatever is returned from the AJAX call (from the controller):
.done(function (response, status, jqxhr) {})
You are doing absolutely nothing, so why would it navigate anywhere.
A better question you need to ask yourself, instead of fixing this, is why would you use AJAX and then navigate to another page. If you are navigating to a whole new page, new URL, then simply submit a form regularly (without AJAX) or do it via a link (which the user will click). Use AJAX post if you want to stay on the same page and refresh the page's contents.
#yas-ikeda , #codingyoshi , #code-first Thank you for your suggestions.
Here are the modifications that I had to make to resolve the problem(please feel free to suggest improvements):
Basically, I had to end up creating 2 separate Action methods to resolve the problem.
In the jquery/Javascript code below, it is important to note the first action method '../Admin/RedirectToNavigateToAParticularResultCodeAssociatedReasonForArrearsList'
function navigateToAParticularResultCodeAssociatedReasonForArrearsList(resultCodeTable_ID) {
console.log(resultCodeTable_ID);
$.ajax({
url: '../Admin/RedirectToNavigateToAParticularResultCodeAssociatedReasonForArrearsList',
type: 'POST',
dataType: 'json',
contentType: "application/json;charset=utf-8",
data: "{'" + "resultCodeTable_IDArg':'" + resultCodeTable_ID + "'}",
cache: false,
}).done(function (response, status, jqxhr) {
window.location.href = response.Url;
})
.fail(function (jqxhr, status, error) {
// this is the ""error"" callback
});
}
The purpose of the 1st action method called '../Admin/RedirectToNavigateToAParticularResultCodeAssociatedReasonForArrearsList' is to retrieve a url within a Json object.
[HttpPost]
public ActionResult RedirectToNavigateToAParticularResultCodeAssociatedReasonForArrearsList(int resultCodeTable_IDArg)
{
var redirectUrl = new UrlHelper(Request.RequestContext).Action("NavigateToAParticularResultCodeAssociatedReasonForArrearsList", "Admin", new { resultCodeTable_IDArg = resultCodeTable_IDArg });
return Json(new { Url = redirectUrl });
}
The purpose of the 2nd action method is to ultimately navigate to the ASP.NET MVC View that I want to show.
public ActionResult NavigateToAParticularResultCodeAssociatedReasonForArrearsList(int resultCodeTable_IDArg)
{
AParticularResultCodeAssociatedReasonForArrearsListViewModel aParticularResultCodeAssociatedReasonForArrearsListViewModel = new AParticularResultCodeAssociatedReasonForArrearsListViewModel();
aParticularResultCodeAssociatedReasonForArrearsListViewModel.ResultCodeTable_ID = resultCodeTable_IDArg;
aParticularResultCodeAssociatedReasonForArrearsListViewModel.RFACodeList = actionCodeResultCodeBusinessService.GetSpecificResultCodeRFACodeList(resultCodeTable_IDArg);
return View("~/Areas/Admin/Views/Admin/AdminModules/Auxiliaries/AParticularResultCodeAssociatedReasonForArrearsList.cshtml", aParticularResultCodeAssociatedReasonForArrearsListViewModel);
}
However, I Dislike the fact that I have to use 2 action methods to navigate to the desired asp.net mvc view, therefore, please feel free to suggest improvements or even a totally different better solution.
I have a page which loads multiple tables separated by TAB using bootstrap.
In the third tab called patient tab, I have an action being done inside a modal.
An ajax call in the view will call an action in controller, when the logic successfully returned to the view, it will call an alert box and to load the latest result set in the table, I put location.reload() function, HOWEVER, the page returns or load in the first TAB and not in the 3rd where I do some action.
Can I specify or force the Tab to be loaded?
here the snippet of the ajax call in view, since it is quite long
}).promise().done(function () {
$.ajax({
type: 'POST',
url: '/Patient/SaveWeight',
dataType: 'json',
contentType: 'application/json',
data: JSON.stringify(add_upd_obj_arr),
dataType: "json",
traditional: true,
success: function (result) {
if (result.errMsg == '' || result.errMsg == "") {
bootbox.alert({
size: "small",
title: "Confirmation!",
message: "Successfully Updated.",
callback: function () {
$('#ModalVitalSign').modal('hide');
location.reload();
}
});
} else {
bootbox.alert(result.errMsg);
}
},
error: function () {
bootbox.alert({
size: "small",
title: "Error!",
message: "There is an error while loading data."
});
}
});
});
I tried this, but does not refresh
window.location.hash = tab_treatment_info; //id of the third tab
I am using Bootbox for my modals and I am having trouble in showing the form validation errors from an Ajax call to the modal. The callback function for the submit button on my modal calls the add_college function to submit the form via Ajax.
When there are validation errors, the modal is populated with validation errors. The problem is that the modal closes regardless if there are validation errors or not. I want the modal to not close only when there are no validation errors.
I know I can just return false in the callback function on my button when there are validation errors to not close it but I have no way of knowing if there are validation errors since I cannot return a value in the Ajax call since it is asynchronous. What is the proper way of doing it?
Here is my code:
$('#new-college-btn').click(function () {
bootbox.dialog({
title: "New College",
message:
''// <Insert long HTML form here>
,
buttons: {
add: {
label: "Add",
className: "btn btn-primary",
callback: function () {
var form_data = {
college_name: $('#college-name').val(),
college_initials: $('#college-initials').val(),
username: $('#username').val(),
password: $('#password').val(),
confirmation_password: $('#confirmation-password').val()
};
add_college(form_data);
}
},
cancel: {
label: "Cancel",
className: "btn btn-default"
}
}
}); // end bootbox dialog
});
function add_college(form_data) {
console.log(form_data);
$.ajax({
url: 'admin/add_new_college',
type: 'POST',
data: form_data,
dataType: 'JSON',
success: function (response)
{
if (response.error) { // there are form validation errors
// populate modal with validation errors here
} else {
// other data processing here
Result.success('College Successfully Added!');
}
},
error: function () {
console.log("fail");
}
});
}
If you want to control when the dialog closes, make sure the callback for your "submit" button always returns false. Then, in the done() (and probably fail()) callbacks for the ajax function, call bootbox.hideAll() to close the dialog (along with any other dialogs you may have opened).
If you want to only close the current dialog, do something along this line:
var dialog = bootbox.dialog({
/* rest of your options... */,
buttons: {
submit: {
label: "Submit",
callback: function() {
var data = [];
$.post('/url', data)
.done(function(result, status, jqxhr){
// if everything went well...
dialog.modal('hide');
})
.fail(function(jqxhr, status, error){
// etc.
});
return false;
}
}
}
});
Basically, create a reference to the dialog, which you can then use inside of the ajax callback.
I want to send textfield data to servlet after clicking button. Textfield and button in tbar of grid. I am using an Ajax request to call a servlet, but it is not calling it.
tbar: [{
xtype: 'textfield',
name: 'text'
}, {
text: 'Serach',
scope: this,
handler: function () {
Ext.Ajax.request({
method: 'GET',
loadMask: true,
scope: this,
url: 'http://localhost:8080/sampleweb/AccessServlet',
success: function (response, request) {
Ext.MessageBox.alert('success', response.responseText);
},
failure: function (response, request) {
Ext.MessageBox.alert('failure', response.responseText);
},
params: {
firstname: text.getValue()
}
});
}
}]
You do not need to put http://localhost:8080 in the AJAX request. Just put AccessServlet as the URL
or /sampleweb/AccessServlet
As others have suggested, what is in the net panel of your browser.
What do you see on the server console ?
You can enable debugging on the server to see the request come in.