I am currently learning asp.net core 3 and I can't find any help regarding this issue that I have.
I have a form that submits a value with a POST request. But I want the same button to have a GET request that populates another field with a .ajax / xmlhttprequest. But I want the POST method to be executed first and then the GET method. Is it possible to do it? I've tried doing it but I got stuck.
These are the methods inside my controller.
[HttpGet]
public async Task<IActionResult> GetConvertedAmount()
{
var rate = await _db.ExchangeRates.Where(x => x.Name.Equals(_tM.Currency)).ToListAsync();
_tM.convertToCurrency(rate[0].Rate);
var amount = _tM.Amount;
return Json(amount);
}
[HttpPost]
public ActionResult CalculateExchangeRatio(int amount_give, string type_to_give)
{
_tM.Amount = amount_give;
_tM.Currency = type_to_give;
return Ok();
}
And this is my JS script
$('#calculateButton').on("click", function () {
$.ajax({
url: "/trade/getconvertedamount",
type: "get",
success: function (amount) {
console.log(amount);
alert(amount);
}
});
})
You can use the $.ajax 'done' chaining to complete the entire process:
$('#calculateButton').on("click", function () {
$.ajax({
url: "/trade/calculateexchangeratio",
data: { amount_give: 9.99, type_to_give: 'blahblah' },
type: "post"
})
.done(function(){
$.ajax({
url: "/trade/getconvertedamount",
type: "get"
})
.done(function (amount) { console.log(amount); alert(amount); });
});
})
You can add the similar to the end of the POST method implementation return RedirectToAction("CalculateExchangeRatio", new { amount_give = 1, type_to_give = 2 });
So your POST method will be called first and it will call the GET method.
Here is the documenttation.
Related
I am trying to pass ID parameter from a view to a controller on a click delete link available on a selected row.
Simplified View Layout
#using (Html.BeginForm("#", "Schedule", FormMethod.Post, htmlAttributes: new { #class = "floating-labels" }))
{
#Html.AntiForgeryToken()
Delete
}
JavaScript
<script type="text/javascript">
function DeleteSchedule(id) {
if (confirm('Are you sure you want to delete this Schedule?')) {
$.ajax({
type: "POST",
url: '#Url.Action("Delete", "Schedule", new { id = "id" })',
contentType: "application/json",
data: { id },
async: true,
cache: false,
success: function (result) { success(result); }
});
}
return false;
}
function success(result) {
$("#ScheduleList").html(result);
}
</script>
Controller
namespace Controllers
{
public class ScheduleController
{
[HttpPost]
[ValidateAntiForgeryToken]
public ActionResult Delete(int id)
{
//do stuff
}
}
}
But on the click of a delete link I get below error and code does not hit controller action.
I am not able to figure out what mistake I am making...
Here is my locally tested implementation that is working.
ScheduleController class:
public class ScheduleController : Controller
{
[HttpPost]
[ValidateAntiForgeryToken]
public IActionResult Delete(int id)
{
return Ok(id);
}
}
Page that sends the post request:
#Html.AntiForgeryToken()
Delete
<div id="ScheduleList"></div>
<script>
function DeleteSchedule(id) {
if (confirm('Are you sure you want to delete this Schedule?')) {
var uri = '/Schedule/Delete?id=' + id;
var tokenElement = document.getElementsByName('__RequestVerificationToken')[0];
var data = {
__RequestVerificationToken: tokenElement.value
}
$.ajax({
type: "POST",
url: uri,
data: data,
success: function (result) {
success(result);
}
});
}
return false;
}
function success(result) {
$("#ScheduleList").html(result);
}
</script>
The page does nothing but render the html, and the javascript handles the actual Ajax post. What I believe you were missing is the Validation token in your request.
It is because you are not actullay posting the form pass it correctly and add _token in the ajax data list and value for that token will come from #Html.AntiforgeryToken()
reading the error the request is most probably send correctly and there is an internal server error as mentioned in the 500 respond so please check the code that is inside the controller
Try this, you are accesing a javascript variable on c# code, and you cant do that.
If correct, please mark as answer.
function DeleteSchedule(id) {
if (confirm('Are you sure you want to delete this Schedule?')) {
var url = '#Url.Action("Delete", "Schedule")?id=' + id;
$.ajax({
type: "POST",
url: url,
contentType: "application/json",
data: { id },
async: true,
cache: false,
success: function (result) { success(result); }
});
}
return false;
}
I think none of the answers above solve the issue. First of all I would replace your target url:
url: '#Url.Action("Delete", "Schedule", new { id = "id" })',
with
url: '#Url.Action("Delete", "Schedule", new { id = actualIdVariable })',
(replace "id" with the actual id variable from the model you're passing to the view).
Note how your browser response is telling you that the url you're posting to is Schedule/Delete/id. That said, I'm not sure you even need the routeValues in this case (the new { id = ...} parameter). this is a POST action, and action parameters wouldn't come from route unless specified by by attribute routing (i.e. [Route("~/Schedule/Delete/{id}")] attribute on your action).
I think your post action is failing because it is trying to parse the "id" string as an int.
Second, I would change the data property of the ajax call and include the anti forgery token. Just because the anchor element you're binding the click event to, is inside the form with #Html.AntiforgeryToken() doesn't mean the generated token will be posted in the ajax request. You're not actually submitting/posting the form, you're just clicking a button.
it should be something like
data: {
'id': id,
'__RequestVerificationToken': $('[name="__RequestVerificationToken"]').val()
}
try this, it solve the error on routing (different url Action) and the parameter on the controller:
JavaScript
<script type="text/javascript">
function DeleteSchedule(id) {
if (confirm('Are you sure you want to delete this Schedule?')) {
$.ajax({
type: "POST",
url: '#Url.Action("Delete", "Schedule")',
data: "id=" + id ,
async: true,
cache: false,
success: function (result) { success(result); }
});
}
return false;
}
function success(result) {
$("#ScheduleList").html(result);
}
</script>
Controller:
[HttpPost]
[ValidateAntiForgeryToken]
public ActionResult Delete(string id)
{
//do stuff
}
Nicola.
MVC application (ASP.NET MVC, client: jquery).
Problem: The second ajax-request wait, when the first ajax request will done.
I need, when the first and the second ajax-requests executes immediatly in one time.
The page sends to server to determine the count of records (the first ajax-request), very long (~5-7 seconds).
The operator click the buttom to open the card to edit it (the second ajax-request, fast, get the Dto-model).
The user doesn't need to wait the first request, he wants to work immediatly.
As a result, in Chrome in network page, two requests in status 'pending'. The second waits the first.
Question, how can I send requests, to execute asynchronously ?
The first ajax-request:
`window.jQuery`.ajax({
type: 'POST',
url: Url.Action("GetCountBooks", "Book");
contentType: "application/json; charset=utf-8",
dataType: 'json',
data: JSON.stringify({ typeBook: "...", filter: "..." };),
success: function (data) {
// show in UI page the count of books by filter and params
},
error: function (data) {
//show error
}});
public class BookController : Controller
{
[HttpPost]
public NJsonResult GetCountBooks(string typeBook, Filter filter)
{
var data = DbProvider.GetCountBooks(typeBook, filter)
if (data.Result == ResultType.Success)
{
var count = data.Data;
return new NJsonResult
{
Data = new { Data = count }
};
}
return new NJsonResult
{
Data = new { Error = "Error while counting the books." }
};
}
}
The second ajax-request:
`window.jQuery`.ajax({
type: 'POST',
dataType: 'json',
contentType: "application/json",
url: Url.Action("GetBookById", "Book"),
data: JSON.stringify({ id: bookId }),
success: function (data) {
// show jquery dialog form to edit dto-model.
},
error: function (data) {
//show error
}});
public class BookController : Controller
{
[HttpPost]
public NJsonResult GetBookById(int id)
{
var data = DbProvider.GetBookById(id)
if (data.Result == ResultType.Success)
{
var book = data.Data;
return new NJsonResult
{
Data = new { Data = book }
};
return new NJsonResult
{
Data = new { Error = "The book is not found." }
};
}
return new NJsonResult
{
Data = new { Error = "Error while getting the book." }
};
}
}
I Cannot union ajax requests into one! The user can send various second request.
You need a fork-join splitter to fork 2 tasks and join based on some condition.
For example here is my implementation:
function fork(promises) {
return {
join: (callback) => {
let numOfTasks = promises.length;
let forkId = Math.ceil(Math.random() * 1000);
fork_join_map[forkId] = {
expected: numOfTasks,
current: 0
};
promises.forEach((p) => {
p.then((data) => {
fork_join_map[forkId].current++;
if (fork_join_map[forkId].expected === fork_join_map[forkId].current) {
if (callback) callback(data)
}
})
});
}
}}
Pass any number of async tasks (promises) into fork method and join when all are done. The done criteria here is managed by simple global object fork_join_map which tracks the results of your fork-join process (global is not good but its just an example). The particular fork-join is identified by forkId which is 0..1000 in this example which is not quite good again, but I hope you got the idea.
With jQuery you can create promise with $.when( $.ajax(..your ajax call) )
In the end you can join your promises like this
fork([
$.when( $.ajax(..your ajax call 1) ),
$.when( $.ajax(..your ajax call 2) )
]).join(() => {
// do your logic here when both calls are done
});
It's my own implementation, there may be already-written library functions for this in jQuery - I dont know. Hope this will give you a right direction at least.
The solution is to add attribute to Asp Controller: [SessionState(System.Web.SessionState.SessionStateBehavior.ReadOnly)]
http://johnculviner.com/asp-net-concurrent-ajax-requests-and-session-state-blocking/
I am using a method in my controller which imports data from an API. This method I am wanted to be called from two locations. First the view (currently working) and secondly a javascript function.
Start of controller method:
[ActionName("ImportRosters")]
[HttpPost]
public ActionResult PerformImportRosterData(int id, int? actualLength, int? rosterLength)
{
var authenticator = Authenticator(id);
var rosters = authenticator.Api().RosterData().ToDictionary(x => x.Id);
var databaseRosterDatas = SiteDatabase.DeputyRosterData.Where(x => x.SiteID == id)
.ToDictionary(x => x.Id);
Javascript Function:
$("#btnDeputyRunNowUpdate").click(function() {
$("#btnRunDeputyNow").modal("hide");
ActualLength = $("#actualRunLength").val();
RosterLength = $("#rosterRunLength").val();
$.ajax({
type: "POST",
url: "/deputy/PerformImportRosterData",
data: { SiteIDRoster, ActualLength, RosterLength }
});
SiteIDRoster = null;
location.reload();
$("#btnRunDeputyNow").modal("hide");
toast.show("Import Successful", 3000);
});
All values are being set but i am getting a 404 error on the url line
POST https://example.org/deputy/PerformImportRosterData 404 ()
I need a way to be able to call this c# method from both html and JS
This can be done if you will modify the URL in your AJAX. It should look something like
url: '<%= Url.Action("YourActionName", "YourControllerName") %>'
or
url: #Url.Action("YourActionName", "YourControllerName")
one more thing, I don't see if you do anything with the result of the call. your script does not have success part
success: function(data) {//do something with the return}
and would be very helpful to have error handler in your call.
full example on how AJAX should look like:
$.ajax({
url: "target.aspx",
type: "GET",
dataType: "html",
success: function (data, status, jqXHR) {
$("#container").html(data);
alert("Local success callback.");
},
error: function (jqXHR, status, err) {
alert("Local error callback.");
},
complete: function (jqXHR, status) {
alert("Local completion callback.");
}
})
For a good tutorial on AJAX read this document
Change after Comment:
my current code is below:
$("#btnDeputyRunNowUpdate").click(function() {
$("#btnRunDeputyNow").modal("hide");
ActualLength = $("#actualRunLength").val();
RosterLength = $("#rosterRunLength").val();
$.ajax({
type: "POST",
url: '<%= Url.Action("PerformImportRosterData", "DeputyController") %>',
data: { SiteIDRoster, ActualLength, RosterLength },
success: function(data) {
console.log(data);
console.log("TESTHERE");
}
});
}
UPDATE:
Noticed one more thing. Your parameters in the controller and AJAX do not match. Please try to replace your a few lines in your AJAX call with:
url: "/deputy/PerformImportRosterData",
data: { id: yourIDValue, actualLength: youractualLengthValue,
rosterLength :yourrosterLengthValue }
remember to set all variable values in javascript , if they have no values set them = to null.
Can you try copy paste code below
$.ajax({
type: "POST",
url: "/deputy/PerformImportRosterData",
data: { SiteIDRoster:999, ActualLength:1, RosterLength:2 }
});
And let me know if it wall cause any errors.
After attempting to solve for a few days, I created a workaround by creating two methods for importing the data. one for the httpPost and the second for import calling from javascript.
Not a great solution but it works. Thanks for your help Yuri
I have a problem when trying to make a request to a url created from mvc, this request is made to an actionresult of a controller, when I am in home ajax if it finds the address, but when I am in a site of my specific system , that is, I am in a section where the url is larger due to other parameters that are in the url, for example in a user profile, there ajax instead of finding the url that is linked to an actionresult return the html page, that is, return the html code, here are my codes
function guardarCalificacion(newidp, ratingp)
{
$.ajax({
type: 'POST',
url: 'saveRating',
data: {
newid: newidp,
rating: ratingp
},
beforeSend: function () {
},
success: function (data)
{
alert(data);
},
error: function ()
{ },
complete: function ()
{ }
});
}
and there are the route
routes.MapRoute(
"saveRating",
"saveRating/{newid}/{rating}",
new { controller = "Home", action = "SaveRating", id = UrlParameter.Optional }
);
in this url if it runs well
http://localhost:49439/Home/index
but in this it is not executed
http://localhost:49439/new/128/busqueda-numero-29
and finally the actionresult
public ActionResult SaveRating(int newid, int rating)
{
return Content(Methods.saveRating(newid, rating).ToString());
}
I have a table that will use is populated by javascript when another table option is clicked. All of this works no problem, when I add the delete button to the table the onClick event fires but this isn't ever called in asp.net.
function DeleteLink(id) {
$.ajax({
url: '/PublicPages/LinkDelete/',
data:{ id:id }
});
}
please tell me where I've gone wrong.
I have tried
function DeleteLink(id) {
$.ajax({
url: '/PublicPages/LinkDelete/' + id
}
as well
UPDATE:
[HttpPost]
public async Task<IActionResult> LinkDelete(Guid id)
{
var pageId = _linkDataProvider.FindById(id).PublicPage.Id;
_linkDataProvider.Delete(id);
var page = await _pageDataProvider.FindById(pageId);
var viewModel = _pageDataProvider.ConvertToViewModel(page);
return View("Details", viewModel);
}
UPDATE2
app.UseMvc(routes =>
{
routes.MapRoute(
name: "default",
template: "{controller=Flooring}/{action=Index}/{id?}");
});
You should specify http method in ajax settings. Try to change your javascript like below:
function DeleteLink(id) {
$.ajax({
type = 'POST',
url: '/PublicPages/LinkDelete/' + id
});
}
Update
If you prefer to use data:{ id:id } then you would need to create a model class:
public class DeleteModel
{
public Guid Id{get;set;}
}
[HttpPost]
public async Task<IActionResult> LinkDelete([FromBody]DeleteModel model)
....