I'm trying to do an AJAX call from my Razor Pages page.
JavaScript:
$.ajax({
type: 'POST',
url: '?handler=Delete',
data: {
id: $(this).data('id')
},
beforeSend: function (xhr) {
// Required for POST, but have same issue if I removed this
// and use GET
xhr.setRequestHeader('XSRF-TOKEN',
$('input:hidden[name="__RequestVerificationToken"]').val());
},
})
.fail(function (e) {
alert(e.responseText);
})
.always(function () {
// Removed to simplify issue
//location.reload(true);
});
Code behind:
public async System.Threading.Tasks.Task OnPostDeleteAsync(int id)
{
string userId = UserManager.GetUserId(User);
var area = DbContext.Areas.FirstOrDefault(a => a.UserId == userId && a.Id == id);
if (area != null)
{
DbContext.Remove(area);
await DbContext.SaveChangesAsync();
}
}
And, in fact, this works correctly and the item is deleted.
However, the $.ajax.fail() handler is called and the error indicates there was a NullReferenceException.
The exception is raised in my markup (CSHTML file):
#if (Model.ActiveAreas.Count == 0) #***** NullReferenceException here! *****#
{
<div class="alert alert-info">
You don't have any active life areas.
</div>
}
The reason there is this exception is because all of the properties of my page model are null. They are null because my OnGetAsync() method is never called to initialize them!
My question is why is my markup executing as though I'm updating the entire page? I'm doing an AJAX call. I don't want to update the entire page. So I don't know why my OnGetAsync() would ever need to be called.
(Based on your provided code)
I think problem in your a always() callback function or the Cliek event or your return statement.
always():
The callback function passed to the always() function is called whenever the AJAX request finishes, regardless of whether or not the AJAX request succeeds or fails. The three parameters passed to the callback function will be either the same three parameters passed to done() or fail(), depending on whether the AJAX request succeeds or fails.
In response to a successful request, the function's arguments are the same as those of .done(): data, textStatus, and the jqXHR object. For failed requests the arguments are the same as those of .fail(): the jqXHR object, textStatus, and errorThrown.
The deferred.always() method receives the arguments that were used to .resolve() or .reject() the Deferred object, which are often very different. For this reason, it's best to use it only for actions that do not require inspecting the arguments. In all other cases, use explicit .done() or .fail() handlers since the arguments will have well-known orders.
Reference:
http://tutorials.jenkov.com/jquery/ajax.html
https://api.jquery.com/jquery.ajax/
https://api.jquery.com/deferred.always/
OR
Cliek event: I think your button is triggering a page refresh. so use preventDefault() in your click event.
Example:
$('...').on('click', function (event) {
event.preventDefault();//add the prevent default.
//Your code
});
OR
Return Statement: If your OnPostDelete method return Page() the please change it to JsonResult or RedirectToPage.
Example:
public Task<IActionResult> OnPostDelete(int? id)
{
if (id == null)
{
return NotFound();
}
//Your Code
return Page();//Remove it
return new JsonResult ("Customer Deleted Successfully!");// Use some thing like it as u need.
return RedirectToPage("./Index");//if u want to reload page then use it.
}
Related
I am trying to mimic an mvc ActionLink. I want the whole row to be clickable. when the actionlink is clicked, it calls the connected controller and executes the code within. I want my Jquery/ajax call to do the same.
I've tried multiple ways of doing this with no luck. I'm currently at a point where the row is clickable and the Jquery sees that, however the ajax call does not execute. Or, if it does, the controller does not execute correctly
Here is the Jquery code that catches the click.
$(document).ready(function () {
$('#policyTable').on('click', '.clickable-row', function (event) {
$(this).addClass('primary').siblings().removeClass('primary');
var Id = $(this).closest('tr').children('td:first').text();
var url = "/Home/ReviewPolicy";
var uc = $(this).closest('tr').children('td:first').text();
alert("Does the click work? " + Id);
$.ajax({
type: "POST",
url: "/Home/ReviewPolicy",
dataType: 'text',
data: { Id: Id }
});
})
})
Here is the controller it is calling:
[HttpPost]
public ActionResult ReviewPolicy(string Id)
{
//Declare policyVM for individual policy
PolicyRenewalListVM model;
int val = Convert.ToInt32(Id);
using (Db db = new Db())
{
//Get the row
PolicyRenewalListDTO dto = db.RenewalPolicies.Find(val);
//confirm policy exists
if (dto == null)
{
return Content("This policy cannot be found.");
}
//initialize the PolicyRenewalListVM
model = new PolicyRenewalListVM(dto);
}
//return view with model
return View(model);
}
When the actionlink itself is clicked (It's not here in the code as I didn't see it being necessary for this problem) it fires and everything works as it should, but the jquery call, sending the very same value (Id) does not.
How to pass jQuery variable value to c# mvc ?
I need to fetch the value of the variable btn in mvc code behind.
$('button').click(function () {
var btn = $(this).attr('id');
alert(btn);
$.ajax({
type: 'GET',
url: '#Url.Action("ActionName", "ControllerName")',
data: { id: btn },
success: function (result) {
// do something
}
});
});
Based on the variable value (Submit Button (or) Preview Button), my model will have Required validation on certain fields.
In my controller , i am calling as
[HttpGet]
public ActionResult ActionName(string id)
{
var vm = id;
return View(vm);
}
Though , ActionResult in controller is not invoked.
Jquery : alert(btn); -- is calling. I can see the alert window showing with the id. However, I am not able to retrieve the id in the controller.
You need to use jQuery.ajax() (or its shortened form jQuery.get()/jQuery.post()) with GET/POST method and set up a controller action with an argument to pass button ID:
jQuery (inside $(document).ready())
$('button').click(function () {
var btn = $(this).attr('id');
var url = '#Url.Action("ActionName", "ControllerName")';
var data = { id: btn };
// if controller method marked as POST, you need to use '$.post()'
$.get(url, data, function (result) {
// do something
if (result.status == "success") {
window.location = '#Url.Action("AnotherAction", "AnotherController")';
}
});
});
Controller action
[HttpGet]
public ActionResult ActionName(string id)
{
// do something
return Json(new { status = "success", buttonID = id }, JsonRequestBehavior.AllowGet);
}
[HttpGet]
public ActionResult AnotherAction()
{
// do something
return View(model);
}
If you want to pass retrieved button ID from AJAX into other action method, you can utilize TempData or Session to do that.
It is a nice coincidence that you use the word "fetch" to describe what you want to do.
jQuery runs in the browser as a frontend framework. Meaning that it runs on the client`s computer. Your MVC-C#-Code lies on the server. Therefore, if you want to send data between those two computers, you need to use the http protocol.
1. Ajax and REST:
Using an ajax call using http methods (post or put) to push your variable value as JSON to the backend`s REST api (route).
For this option, you might want to have a look at the fetch function of javascript.
2. HTML Forms
Use a html form where you store the variable value inside one input element. A form submission will perform a http post (by default) request to the backend as well and use all input element values as post parameters.
There are many ways to accomplish what you are looking to do, but I'll stick to using your code sample.
So what you need to do is utilize the .ajax call in jquery to send data from your view to your controller. More on that here: http://api.jquery.com/jquery.ajax/
Using your code, you'd put the .ajax call within your logic flow of what to do based on which button is clicked.
$("button").click(function ()
{
var btn = this.id;
if (btn == "previewButton")
{
$.ajax({
url: "/MyApp/MyAction",
type: "POST",
data: { btnId: btn },
dataType: "json",
async: true,
cache: false
}).success(function(data){
// do something here to validate if your handling worked
}).error(function(){
// Do something here if it doesnt work
});
}
}
You'll see that there is a URL. In my example i've chose MyApp as my controller and MyAction as the method of the controller in which we are posting values to. The ajax call posts 1 parameter with a property of btnId. If you need to pass more data, the property name in the jquery call should correspond with an argument of the actions method signature within the controller.
So my controller looks like
public MyAppController : Controller
{
[HttpPost]
public JsonResult MyAction(string btnId)
{
Debug.WriteLine("btnId: {0}", btnId);
return Json(new{ ButtonId= btnId });
}
}
This would be one way to handle passing values from your view to your controller using .ajax calls with jquery.
My preferred way is to use the Html helpers of Ajax.BeginForm which could be another option for you.
https://www.aspsnippets.com/Articles/ASPNet-MVC-AjaxBeginForm-Tutorial-with-example.aspx
I reallly have a simple set of code to bring back a set of data that is triggered off a drop down.
this is the script:
function () {
$('#ProviderID').change(function () {
$.ajax({
url: '/servicesDisplay/Index',
type: 'Get',
data: { id: $(this).attr('value') },
success: function (result) {
// The AJAX request succeeded and the result variable
// will contain the partial HTML returned by the action
// we inject it into the div:
$('#serLocations').html(result);
}
});
});
This is the controller:
public ActionResult Index(string id)
{
int prid = Int32.Parse(id.Substring(0, (id.Length-1)));
string mulitval = id.Substring((id.Length-1), 1).ToString();
System.Data.Objects.ObjectResult<getProviderServiceAddress_Result> proList = theEntities.getProviderServiceAddress(prid);
List<getProviderServiceAddress_Result> objList = proList.ToList();
SelectList providerList = new SelectList(objList, "AddressID","Address1");
//ViewBag.providerList = providerList;
return PartialView("servicesDisplay/Index", providerList);
}
This is the view:
#model OCS_CS.Models.servicesDisplay
<div>
#Html.DropDownList(model => model.ServiceAdderssID, (IEnumerable<SelectListItem>)model)
</div>
When the drop down passes the in the value. The apps does hit the controller. But it highlightes the drop down in a light red and the view never displays.
Try this short version which uses the jquery load method.
$(function(){
$('#ProviderID').change(function () {
$('#serLocations').load("#Url.Action("Index","ServicesDisplay")?id="
+$(this).val());
});
});
If you want to avoid caching of result, you may send a unique timestamp along with the querystring to avoid caching.
$('#serLocations').load("#Url.Action("Index","ServicesDisplay")?id="
+$(this).val()+"&t="+$.now());
You are doing a GET, thats no meaning to pass data to ajax, you may pass data for POST:
First, put the value at the URL:
function () {
$('#ProviderID').change(function () {
$.ajax({
url: '/servicesDisplay/Index/' + $(this).attr('value'),
type: 'Get',
success: function (result) {
// The AJAX request succeeded and the result variable
// will contain the partial HTML returned by the action
// we inject it into the div:
$('#serLocations').html(result);
}
});
});
Second, mark the method as GET
[HttpGet]
public ActionResult Index(string id)
Hopes this help you!
You have quite a few problems with your code. First the model defined for your view is:
#model OCS_CS.Models.servicesDisplay
but in your action your're invoking the call to this view by passing in a SelectList:
SelectList providerList = new SelectList(objList, "AddressID","Address1");
return PartialView("servicesDisplay/Index", providerList);
this is not going to fly because the models do not match by type. Seconds problem is you are casting this SelectList into an IEnumerable. This is also not going to work. You need to cast to SelectList:
#Html.DropDownList(model => model.ServiceAdderssID, (SelectList)model)
but again until you match the type of your model in your action with the model on your view none of this will work. I suggest you install Fiddler to help you determine what sort of error are you getting.
I have an ASP .NET MVC application, additonally I am using Knockout 2.0.0. I created a partial view which I would like to render to the page using knockout. The partial needs to be rendered within a Knockout foreach statement. I am unable to get the knockout HTML binding to work, and so I'm currently using a hack to put the html into the div using JQuery.
There is a lot of html on this page, so it's not possible to post all of the source code, so I will try and post the pertinent code:
<div data-bind="foreach:issues">
#* SNIP - A lot of other html here*#
<div id="myPartialDiv" data-bind="html: $parent.getHtml(issueId())">
</div>
</div>
Further down I have the following javascript function on my KO View Model (I have commented out my hack and included the code that returns HTML):
var getHtml = function (issueId) {
var baseUrl = '#Url.Action("GetHtmlAction","MyController")';
$.ajax(
{
type: "POST",
url: baseUrl,
data: "&issueId=" + issueId,
success: function (data) {
//$('#mypartialDiv').html(data);
return data;
},
error: function (req, status, error) {
//$('#myPartialDiv').html('Something went wrong.');
return 'Something went wrong.'
},
dataType: "text"
});
}
The code above results in no data being rendered to the page. USing Chrome debug tools, I see that there are no javascript errors occuring, and knockout is simply not binding the html of the div to the results returned from the getHtml function.
What am I doing wrong?
Thanks
As Miroslav Popovic explains, the problem is that the AJAX request is asynchronous, so the return data is ignored and there is no return value from your call to getHtml.
I would suggest using a custom binding that handles the asynchronous HTML loading (I've put a working example here).
This works by taking 2 parameters to the asyncHtml: a function to call that takes a success callback as it's final parameter (plus any other parameters) and an array of the parameters that need to be passed to that function.
<div id="myPartialDiv" data-bind="asyncHtml: { source: getHtml, params: [123] }">Loading...</div>
The custom binding then grabs these values, concats a custom callback onto the parameters that are passed to it, and calls the specified function:
ko.bindingHandlers.asyncHtml = {
init: function(element, valueAccessor) {
var value = ko.utils.unwrapObservable(valueAccessor());
var parameters = value.params.concat([function(data) {
$(element).html(data);
}]);
value.source.apply(null, parameters);
}
};
Finally we can re-implement our view model HTML-retrieving method to make the POST call and invoke the new success handler:
var ViewModel = function() {
this.getHtml = function(issueId, callback) {
$.ajax(
{
type: "POST",
url: "/echo/html/",
data: {
html: "<p>server response " + issueId + "</p>",
delay: 1
},
success: callback,
dataType: "text"
});
};
};
Note: for this example I am using the jsFiddle echo to post back a random response
$.ajax is an asynchronous call. When you call it, the execution will just continue to the next statement in the getHtml function. Since this is the last statement, the getHtml function will return undefined.
About your return data;... This return is within a success callback function. The data will be result of that function, not the parent getHtml function. Besides, getHtml is already completed. You can't return a result from it.
How about having an observable property in your view model called html, and then find some other means of triggering the getHtml function (button click, some other success callback, issueId property change...), that will in turn set the 'html' property value. Then you could simply data-bind to that property data-bind="html: html".
Given a method..
public ActionResult Method()
{
// program logic
if(condition)
{
// external library
// external library returns an ActionResult
}
return View(viewname);
}
I cannot control the return type or method of the external library. I want to catch its results and handle that in a dialog on the page - but I cannot figure out how to get back to the page to execute the jQuery that would be responsible for it. Any ideas?
You can call Method() by just routing your jQuery .ajax() request to it. Since it's just returning straight up html, make sure you set your response type to expect that, and then your jQuery callback handler will have to deal with the resulting html. For example,
$("#myButton").click({
$.ajax({
// Basic ajax request properties
url: /* route to call Method() */,
data: {}
dataType: "html",
type: "GET",
success: function(objResponse){
alert(objResponse); // alerts the html of the result
/* Deal with response here, put the html in a dialog */
}
})
});