Call server method without page reload with razor page - c#

In my .net core razor page project, i would like to call server side methods from a cshtml input without reloading the page. I'm still a newbie with razor pages.
.cshtml :
input type="submit" id="AddCart" asp-page-handler="AddToCart" hidden
Some JS to .click() the input.
.cs :
public async void OnPostAddToCart()
{
//code
}
So far i did not find a way to prevent the page reload and still access my server-side methods.
Thanks
EDIT :
Looking at the link provided by brad, i managed to make it work.
I added #Page "{handler?}" to write the url without the handler (not sure if it matters for ajax),
I set my ajax url to "thePage/theMethod",
I decorated my razor controller class with [ValidateAntiForgeryToken]
And mentioned the anti forgery token in ajax :
$.ajax({
url: "/mainPage/AddToCart",
type: "POST",
contentType: "application/json; charset=utf-8",
beforeSend: function (xhr) {
xhr.setRequestHeader("XSRF-TOKEN",
$('input:hidden[name="__RequestVerificationToken"]').val());
},
success: function () {
alert("success");
},
complete: function () {
alert("complete")
},
failure: function () {
alert("failure");
}
});

First ,change the naming of your Handler method like below :
public async void OnPostAddToCartAsync()
{
//code
}
Refer to Handler Methods in Razor Pages for more details on the nameing convention .
Second ,If you want to use ajax in Razor Pages , the URL pattern should be like "/mainPage?handler=AddToCart" .One thing to note down is, Razor Pages are designed to be protected from (CSRF/XSRF) attacks. Hence, Antiforgery token generation and validation are automatically included in Razor Pages. I believe that is the problem here. Your page may have antiforgery token present on the page if you have form tag in your HTML. But you need to pass the same in your Ajax request.
Add antiforgery token using #Html.AntiForgeryToken(), if not
present.
Modify your Ajax request to send the same in request header like
below:
<input type="button" id="AddCart" onclick="clickbtn()" value="Submit"/>
function clickbtn() {
$.ajax({
url: "/Test?handler=AddToCart",
type: 'POST',
beforeSend: function (xhr) {
xhr.setRequestHeader("X-XSRF-TOKEN",
$('input:hidden[name="__RequestVerificationToken"]').val());
},
success: function ()
{
alert("success");
},
complete: function ()
{
alert("complete")
},
failure: function ()
{
alert("failure");
}
});
}
Since the script sends the token in a header called X-XSRF-TOKEN,
configure the antiforgery service to look for the X-XSRF-TOKEN
header:
services.AddAntiforgery(option => option.HeaderName = "X-XSRF-TOKEN");
Read this post Handle Ajax Requests in ASP.NET Core Razor Pages to know more about making ajax request with ASP.NET Core razor pages.

If you do not want to reload the page you must use ajax or XMLHttpRequest , (the former being based on the latter).
<script>
window.onload=function()
{
window.click=function()
{
$.ajax({
url: '[baseUrl/OnPostAddToCart]',
data: JSON.stringify(postData), //your data
type: 'POST',
contentType: 'application/json',
dataType: 'json',
success: function (result) {
alert(result); //do something if successful
},
complete: function(){
//do something on complete
},
failure: function (err) {
alert(err); // Display error message
}
});
}
}
</script>
<input onclick="click()" type="button"/>
Using XMLHttpRequest:
window.click=function()
{
var xhr = new XMLHttpRequest();
xhr.open("POST", "[Your URL]");
xhr.onload=function()
{
if(xhr.status==200)
resolve(xhr.response);
else
reject("error:"+xhr.status);
}
var data=JSON.stringify({some_data});
xhr.send(data);
}
Controller method
public class MyController:Controller
{
[HttPost]
[Route("/OnPostAddToCart")]
public async Task AddToCart(object data)
{
}
}
P.S For more information on ajax

Related

Ajax Post not finding method in page model

I have the following method inside my page model which is called Order
public async Task<IActionResult> OnPostAddRecord(string recordId)
{
return new JsonResult("Hello");
}
My Ajax code to call said method:
$('#RecordList').change(function () {
var formData = {
recordId: $("#RecordList").val(),
};
$.ajax({
type: 'POST',
data: formData,
url: '#Url.Page("order", "addrecord")',
success: function (result) {
alert(result)
},
error: function (result) { }
});
});
Yet when it's fired it returns StatusCode 400, however, I have another Ajax method on the same page that works successfully, the difference is that one is a GET whereas this is a POST.
I really can't see what the problem is here.
You need to include the request verification token in your FormData: https://www.mikesdotnetting.com/article/336/ajax-posts-in-razor-pages-and-http-400-errors

jQuery AJAX Request returning HTML instead of JSON Result (Razor Pages)

I'm having trouble extracting data from an AJAX request in ASP.NET Core Razor Pages.
Ajax Request Code (contained in a <script> block on a razor pages .cshtml page:
$("body").ready(function AjaxTest() {
$.ajax({
contentType: 'application/json; charset=utf-8',
dataType: 'text',
url: '/Menus/Admin_MainMenu?action=TestMethod',
method: 'GET',
success: function (data) {
alert("Request Successful" + data);
},
error: function () {
alert("Request Failed");
}
});
})
And the corresponding PageModel method (just as test at the moment):
[HttpGet]
public string TestMethod()
{
string mystring = "success";
return mystring;
}
I know the request works, as I get the alert "Request Successful". However, instead of "Request Successful" being followed by my value of mystring, I get a string of HTML corresponding to the layout of the .cshtml page.
I've tried changing the data type to JSON (both in the AJAX request using dataType, and in the method return type (jsonrequest), but that makes the request fail.
Any help is greatly appreciated. Thanks.
The problem when using dataType: 'text' is that the string may rendered as HTML output instead of simple string. Also declaring function AjaxTest() inside ready event is not a proper way to declare function inside AJAX callback, even the syntax is valid because of scoping issue.
You need to use JsonResult return type instead of string:
public JsonResult OnGetTestMethod()
{
string mystring = "success";
return new JsonResult(mystring);
}
Then use handler parameter inside AJAX call:
$(document).ready(function () {
$.ajax({
dataType: 'json',
url: '/Menus/Admin_MainMenu?handler=TestMethod',
type: 'GET',
success: function (data) {
alert("Request Successful " + data);
},
error: function () {
alert("Request Failed");
}
});
});
Note:
1) The JsonResult mentioned here is not System.Web.Mvc.JsonResult, it uses Microsoft.AspNetCore.Mvc.JsonResult and doesn't have JsonRequestBehavior property.
2) Razor pages uses OnGet and OnPost action method prefixes to deal with HTTP GET and POST respectively, hence the [HttpGet] attribute is unnecessary.
Further references:
Handle Ajax Requests in ASP.NET Core Razor Pages
ASP.NET Core Razor Pages: How to implement AJAX requests

Ajax can't find my function in Controller url/path is wrong(orchard)mvc

Hello i have build ajax that call my function in Control.
this project in Orchard(new in that) it is like mvc as i know.
I have problem with url/path to the function.
if i use url: '#Url.Action("GetFilesList", "FileUpload")' NOT working
I know that in '#Url.Action first value is my function name , and secont is my controller name(without controller it self)
but like that with direct url to function it is working
'http://localhost:30321/OrchardLocal/VnModule.Module/FileUpload/GetFilesList'
This my code:
Work:
$.ajax({
url: 'http://localhost:30321/OrchardLocal/VnModule.Module/FileUpload/GetFilesList',
type: 'POST',
data: {
sNum: "123",
__RequestVerificationToken: token
},
success: function () {
},
error: function () {
}
});
And this is not working:
$.ajax({
url:'#Url.Action("GetFilesList", "FileUpload")',
type: 'POST',
data: {
sNum: "123",
__RequestVerificationToken: token
},
success: function () {
},
error: function (xhr) {
}
});
My controller:
namespace VnModule.Module.Controllers
{
public class FileUploadController : Controller
{
[HttpPost]
[ValidateAntiForgeryToken]
[ActionName("GetFilesList")]
public void GetFilesList(string sNum)
{
int myNumber = Int32.Parse(sNum);
}
}
}
Sow i sure that problem is in url: '#Url.Action("GetFilesList", "FileUpload")' but i cant understand what i am doing wrong.
Do you have any ideas?
Orchard Documentation link about module
Every module in Orchard CMS is an area of ASP.NET MVC project. So You need to add area attribute in your code like as:
url: '#Url.Action("GetFilesList", "FileUpload", new{area = "module name here"})'
This way your problem should be solved.
Check your URL in network panel and identified which URL is called in ajax request It's help you a lot to find a solution and as per orchard if it is required to pass area then change #Url.Action accordingly.
I found the solution how to see the url ( Url.Action razor) , in external js file;
i have added data-id with this path to my button like this:
<input type="submit" value="Savee" id="btn_UploadImg" onclick="btn_Upload_Click(this)" data-urlaction="#Url.Action("GetFilesList", "FileUpload", new { area = "VnModule.Module" })" />
And to get this Url Action path in external js file you can like this:
var funcUrl = $("#btn_UploadImg").data("urlaction");
$.ajax({
url: funcUrl,
type: 'POST',
data: {
sNum: "123",
__RequestVerificationToken: token
},
success: function () {
},
error: function (xhr) {
alert("Error:"+xhr.responseText);
console.log(xhr.responseText);
console.info(xhr);
}
});

Search data in table using ajax in ASP.net MVC

I want to display data in a table based on the search criteria in a textbox. I have implemented it without using Ajax but do not know how to call controller method using jquery and update table data. Please try to solve my problem. Thanks...
Index.cshtml
#model IEnumerable<MvcApplication4.Models.tbl_product>
#{
Layout = null;
}
<!DOCTYPE html>
<html>
<head>
<script src="#Url.Content("~/Scripts/jquery-1.5.1.js")" type="text/javascript"></script>
<title>Index</title>
<script type="text/javascript">
$(document).ready(function () {
$('#Button1').click(function () {
alert("button clicked");
$.ajax({
type: 'POST',
contentType: "application/json; charset=utf-8",
url: 'Home/Index',
data: "{'searchString':'" + document.getElementById('searchString').value + "'}",
async: false,
Success: function (response) {
alert("Success");
window.location.reload();
},
error: function () { alert("error"); }
});
});
});
</script>
</head>
<body>
#* #using (#Html.BeginForm("Index", "Home"))
{*#
#Html.TextBox("searchString");
<input type="button" value="filter" id="Button1" />
#* }*#
<table id="showData">
#{Html.RenderPartial("SearchList");}
</table>
</body>
</html>
SearchList.cshtml(Partial View)
#foreach (var item in Model)
{
<tr>
<td>#item.ProductName</td>
<td>#item.ProductId</td>
<td>#item.ProductDesc</td>
</tr>
}
HomeController.cs
public class HomeController : Controller
{
//
// GET: /Home/
ProductEntities dbentity = new ProductEntities();
public ActionResult Index()
{
return View(dbentity.tbl_product.ToList());
}
[HttpPost]
public ActionResult Index(string searchString)
{
var query = dbentity.tbl_product.Where(c => c.ProductName.Contains(searchString));
return View(query.ToList());
}
}
$.ajax({
url: '/ControllerName/ActionName',
type: "POST",
data: {criteria: 'criteria'},
contentType: "application/json",
success: function (data) {
//Replace existing table with the new view (with the table).
}
});
//write ControllerName without the key controller.
$.ajax({
type: 'POST',
contentType: "application/json; charset=utf-8",
url: 'Home/Index',
data: JSON.stringify({'searchString':document.getElementById('searchString').value }),
async: false,
Success: function (response) {
alert("Success");
//append the data in between table tbody like,
$('table tbody').html(response);
//No window.location.reload(); It will cause page reload initial data will appear in grid.
},
error: function () { alert("error"); }
});
return false
Hope this helps.
Your ajax request should look like:
$.ajax({
url: '/<ControllerName>/<MethodName>',
type: "POST",
data: requestData,
contentType: "application/json;charset=utf-8",
success: function (data, textStatus, XMLHTTPRequest) {
//Success callback handling
},
error: function (XMLHTTPRequest, textStatus, errorThrown) {
//Error callback handling
},
cache: false //whether you want to cache the response or not.
});
I'm not going to give you the exact answer, but to help you to get it.
There are two steps:
First you must get sure the request is being done, and the response is being get on the browser.
To do so, you can
do it on your way: leave only the alert("Success"); and check it's being run.
better than that, open the browser's developer console (I prefer Chrome, but you can also use IE or FireFox + FireBug add-on) using F12. Set breakpoints and inspect variable values and code flow. See thit tutorial for Chrome developer tools.
set a breakpoint on the server action, and check it's executed
Second Once you're sure the firs part is working fine, use your succes function to replace the table content with the data received in the response. You can do it in several ways with jQuery. For example
$('#showData').html(response);
Again, you can execute this code and inspect the contents of response from the developer's console in your browser. This makes things eaiser when you're starting to use javascript.
(If your action generated the whole table, you could use jQuery's replaceWith which replaces the target, instead of its content. Don't use this for this case).
FINAL NOTE: please, remove this code window.location.reload();!!! This reloads the whole page with the current URL, so whatever thing you do in advance will be lost.

ASP .NET MVC3 ajax call same function from various pages

How can I call the same action using ajax from different pages?
type: 'POST',
url: 'Notification/GetRecentNotifications/'
I'm currently using the code above to call my action. It works for my application's home page, but when I change to other page, this doesn't work. Can anybody give me a solution? Thanks before.
Heres what I usually do to point to which controller & action to call within an ajax jquery call...
$.ajax({
type: "POST",
url: '#(Url.Action("Action", "Controller"))',
success: function (data) {
}
});
Use Url.Action() to build links
Put the code in a ajax.js file in your scripts directory then reference it in the pages where you need to use the methods in that file. Then, put any server side logic for your ajax calls in an AjaxController For example:
ajax.js
function foo() {
var model = { };
$.ajax({
url: '#Url.Action("Foo", "Ajax")',
type: "POST",
data: JSON.stringify(model),
success: function(data) {
alert(data);
},
error: function(data) {
alert(data);
}
});
}
AjaxController.cs
public class AjaxController : Controller
{
[HttpPost]
public JsonResult Foo(FooModel model)
{
string message = _ajaxService.Foo(model);
return Json(message);
}
}
In the example above _ajaxService is a service layer object that contains the logic to handle your ajax requests. Below is how to use the function in your view:
SomeView.cshtml
<script type="text/javascript" language="javascript" src="#Url.Content("~/Content/Scripts/ajax.js")"></script>
<script type="text/javascript" language="javascript">
$(document).ready(function () {
$('#button').click(foo);
});
</script>
If there is additional logic to pass data to the ajax method that is reused, you should probably put it in a partial view and reference that from every view that needs it.

Categories