I have a form with a single textbox. The field bound to that textbox is required.
When I post the form with that textbox empty I get ModelState.IsValid = False
as expected. But, the form still fires the data-ajax-success
.
Relevant .cshtml
<form method="post" asp-page-handler="ProductAliasCreate" data-ajax="true" data-ajax-method="post" data-ajax-success="refreshPartial('GetAliases', 'product-aliases-container')" data-ajax-failure="handleError">
Relevant .cshtml.cs
public async Task<IActionResult> OnPostProductAliasCreateAsync()
{
if (!ModelState.IsValid || _context.ProductAliases == null || ProductAlias == null)
{
return Page();
}
_context.ProductAliases.Add(ProductAlias);
await _context.SaveChangesAsync();
return Page();
}
It's hitting that first return Page();
inside that Isvalid
check.
How do I prevent the data-ajax-success
callback from firing when ModelState.IsValid = false
?
Note: I previously had the refreshPartial
callback in the data-ajax-complete
with the same result...so I moved it to data-ajax-success
thinking that'd be the solution to this issue.
Return Page() would always return response with 200 statue code in your senaro,if you want fire data-ajax-success
when modelstate is invalid,you should return response with 400 statuecode
A minimal example,hopes help:
PageModel:
public class MyEntityModel : PageModel
{
[BindProperty(SupportsGet =true)]
public MyEntity? MyEntity { get; set; }
public void OnGet()
{
}
public async Task<IActionResult> OnPostProductAliasCreateAsync()
{
if (!ModelState.IsValid )
{
return BadRequest();
}
return new OkObjectResult("");
}
}
Page:
@page
@model MyEntityModel
@{
}
<form method="post" asp-page-handler="ProductAliasCreate" data-ajax="true" data-ajax-method="post" data-ajax-success="success()" data-ajax-failure="fail()">
Id:
<input asp-for="MyEntity.Id" />
Name:
<input asp-for="MyEntity.Name" />
<input type="submit" />
</form>
<script src="~/lib/jquery/dist/jquery.min.js"></script>
<script src="~/lib/jquery-ajax-unobtrusive/jquery.unobtrusive-ajax.js"></script>
<script>
function success() {
console.log("success")
}
function fail(){
console.log("fail")
}
</script>
Result:
Update based on your comment:
If you've passed client validation(in my case,null check) and got model state error on server(for example,duplicated Name)
If you want to show the errors ,you have to refresh the page yourself due to ajax call
My solution:
create a filter:
public class MyPageFilter : IPageFilter
{
public void OnPageHandlerSelected(PageHandlerSelectedContext context)
{
}
public void OnPageHandlerExecuting(PageHandlerExecutingContext context)
{
}
public void OnPageHandlerExecuted(PageHandlerExecutedContext context)
{
if (context.ModelState.ErrorCount != 0)
{
context.HttpContext.Response.StatusCode = 400;
}
}
}
PageModel:
[TypeFilter(typeof(MyPageFilter))]
public class EntityModel : PageModel
{
private readonly MyRazorPageApp.Areas.Identity.Data.MyRazorPageAppContext _context;
private readonly ICompositeViewEngine _viewEngine;
public EntityModel(MyRazorPageApp.Areas.Identity.Data.MyRazorPageAppContext context, ICompositeViewEngine viewEngine)
{
_context = context;
_viewEngine = viewEngine;
}
public IActionResult OnGet()
{
return Page();
}
[BindProperty]
public MyEntity MyEntity { get; set; } = default!;
// To protect from overposting attacks, see https://aka.ms/RazorPagesCRUD
public async Task<IActionResult> OnPostAsync()
{
ModelState.AddModelError("MyEntity.Name", "Not Valid");
if (!ModelState.IsValid || _context.MyEntity == null || MyEntity == null)
{
return Page();
}
return RedirectToPage("./Index");
}
}
Page:
@page
@model MyRazorPageApp.Pages.EntityModel
@{
}
<h1>Enyity</h1>
<h4>MyEntity</h4>
<hr />
<div class="row">
<div class="col-md-4">
<form method="post" data-ajax="true" data-ajax-method="post" data-ajax-success="success" data-ajax-failure="fail">
<div asp-validation-summary="ModelOnly" class="text-danger"></div>
<div class="form-group">
<label asp-for="MyEntity.Name" class="control-label"></label>
<input asp-for="MyEntity.Name" class="form-control" />
<span asp-validation-for="MyEntity.Name" class="text-danger"></span>
</div>
<div class="form-group">
<label asp-for="MyEntity.Prop" class="control-label"></label>
<input asp-for="MyEntity.Prop" class="form-control" />
<span asp-validation-for="MyEntity.Prop" class="text-danger"></span>
</div>
<div class="form-group">
<input type="submit" value="Create" class="btn btn-primary" />
</div>
</form>
</div>
</div>
<div>
<a asp-page="Index">Back to List</a>
</div>
<div id="mydiv"></div>
<script src="~/lib/jquery/dist/jquery.min.js"></script>
<script src="~/lib/jquery-validation/dist/jquery.validate.js"></script>
<script src="~/lib/jquery-ajax-unobtrusive/jquery.unobtrusive-ajax.js"></script>
<script src="~/lib/jquery-validation-unobtrusive/jquery.validate.unobtrusive.min.js"></script>
<script>
function success() {
console.log("success")
}
fail=function (response) {
console.log("fail")
var newDoc = document.open("text/html", "replace");
newDoc.write(response.responseText);
newDoc.close();
}
</script>