I'm trying to do an AJAX call from my Razor Pages page.
$.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);
});
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.
I think the problem is either in:
always()
callback functionClick
eventFrom Jakob Jenkov's tutorial on jQuery AJAX:
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 todone()
orfail()
, depending on whether the AJAX request succeeds or fails.
From the jQuery .ajax()
documentation:
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.
From the jQuery deferred.always
documentation:
Note: The
deferred.always()
method receives the arguments that were used to.resolve()
or.reject()
theDeferred
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.
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
});
If your OnPostDelete
method has return Page()
, then please change it to JsonResult
or RedirectToPage
.
Example:
public Task<IActionResult> OnPostDelete(int? id)
{
if (id == null)
{
return NotFound();
}
//Your Code
return Page(); //Remove this line
return new JsonResult ("Customer Deleted Successfully!"); // Use something like this as needed.
return RedirectToPage("./Index"); //if you want to reload page then use this.
}