I am trying to save a ViewModel object from a partial view in a modal, and I get a 404 error when I try to post it. The url is being called, but the ViewModel data isn’t being sent. I have been reading similar questions on here and on MSN for hours and nothing I’ve tried fixes the problem. I took out the repetitive days of the week code for brevity, but I can
add them back in if anyone wants a complete working example. Here is the code
EmployeeViewModel
public class EmployeeViewModel
{
public bool Monday { get; set; } = false;
//...bool properties for Tuesday through Sunday
public Employee Employee { get; set; }
}
Employee/ _AddEmployeeModalPartial
@model JSarad_C868_Capstone.ViewModels.EmployeeViewModel
@Html.AntiForgeryToken()
<div class="modal modal-fade" id="addEmployee">
<div class="modal-dialog">
<div class="modal-content">
<div class="modal-header">
<h4 class="modal-title" id="addEmpoyeeLabel">Add Employee</h4>
<button type=button class="close" data-bs-dismiss="modal">
<span>x</span>
</button>
</div>
<div class="modal-body">
<form action="Add">
<div class="form-group">
<input asp-for="Employee.Id" class="form-control" />
<input asp-for="Employee.Availability" class="form-control" />
<label asp-for="Employee.Role"></label>
<select asp-for="Employee.Role" class="form-control">
<option value="Bartender">Bartender</option>
<option value="Server">Server</option>
</select>
<span asp-validation-for="Employee.Role" class="text-danger"></span>
</div>
@*<div class="mb-3">*@
<div class="form-group">
<label asp-for="Employee.Name"></label>
<input asp-for="Employee.Name" class="form-control" />
<span asp-validation-for="Employee.Name" class="text-danger"></span>
</div>
@* <div class="mb-3">*@
<div class="form-group">
<label asp-for="Employee.Phone"></label>
<input asp-for="Employee.Phone" class="form-control" />
<span asp-validation-for="Employee.Phone" class="text-danger">
</span>
</div>
@*<div class="mb-3">*@
<div class="form-group">
<label asp-for="Employee.Email"></label>
<input asp-for="Employee.Email" class="form-control" />
<span asp-validation-for="Employee.Email" class="text-danger">
</span>
</div>
@*<div class="mb-3">*@
<div class="form-group">
<label asp-for="Employee.Address"></label>
<input asp-for="Employee.Address" class="form-control" />
<span asp-validation-for="Employee.Address" class="text-danger">
</span>
</div>
@* <div class="mb-3">*@
<div class="form-group">
<label>Availabiliy</label>
</div>
<div class="row pb-4">
<div class="col">
<div class="form-check">
<input asp-for="Monday" class="form-check-input"
type="checkbox" />
<label asp-for="Monday" class="form-check-label"></label>
</div>
<!--...//form check boxes for Tuesday trough Sunday -->
</div>
</div>
</form>
</div>
<div class="modal-footer">
<button type="button" class="btn btn-primary"
data-bs-dismiss="modal">Cancel</button>
<button type="button" class="btn btn-primary"
data-bs-save="modal">Save</button>
</div>
</div>
</div>
</div>
EmployeeController.cs
[HttpGet]
public IActionResult Add()
{
EmployeeViewModel viewModel = new EmployeeViewModel();
return PartialView("_AddEmployeeModalPartial", viewModel); ;
}
[HttpPost]
[ValidateAntiForgeryToken]
public IActionResult Add(EmployeeViewModel viewModel) //code never reaches this Action
{
viewModel.Employee.Availability = ConvertDaysToChar(viewModel.Employee.Availability)
if (ModelState.IsValid)
{
_db.Employees.Add(viewModel.Employee);
_db.SaveChanges();
return RedirectToAction("Index");
}
else
{
return PartialView("_AddEmployeeModelPartial", viewModel);
}
}
site.js
$(function () {
var PlaceHolderElement = $('#PlaceHolderHere');
$('button[data-bs-toggle="ajax-modal"]').click(function (event) {
/* event.preventDefault();*/
var url = $(this).data('url');
console.log(url)
$.get(url).done(function (data) {
PlaceHolderElement.html(data);
PlaceHolderElement.find('.modal').modal('show');
})
})
PlaceHolderElement.on('click', '[data-bs-save="modal"]', function (event) {
event.preventDefault();
var form = $(this).parents('.modal').find('form');
var actionUrl = form.attr('action');
console.log(actionUrl);
var sendViewModel = form.serialize();
console.log(sendViewModel);
//$.post(actionUrl, sendViewModel).done(function (data) {
// PlaceHolderElement.find('.modal').modal('hide');
/*above is the code from a tutorial for modals. It also doesn't send the object to
post action*/
$.ajax({
type: 'POST',
url: actionUrl,
dataType: 'json',
contentType: 'application/json',
data: JSON.stringify(sendViewModel),
success: function (result) {
console.log('Data received: ');
console.log(result);
}
})
})
})
When I click the save button on the model, the console.log(sendViewModel) returns the correct Serialization with all of the properties and their correct names. And the properties change correctly when there is input.
Employee.Id=&Employee.Availability=&Employee.Role=Bartender&Employee.Name=&Employee.Phone=&Employee.Email=&Employee.Address=&Monday=false&Tuesday=false&Wednesday=false&Thursday=false&Friday=false&Saturday=false&Sunday=false
But I get an error "Failed to load resource: the server responded with a status of 404 ()"
and when I check it the page says "No webpage was found for the web address: https://localhost:44313/Add HTTP ERROR 404" as if it’s trying to get a post. It is also missing the controller, but if I change my form action to "Employee/Add" in the _Partial view it still doesn’t send the data along with the url, which is causing an entirely different problem. I would greatly appreciate any help or guess or input of any kind. I’m about five seconds away from throwing my laptop out the window on this one. Thanks.
2
Answers
First, I had to change the form action from "Add" to "Employee/Add". ThenI had to remove the antiforgery token from my post action. The first code that is commented out actually works fine otherwise. In my defense I did remove the antiforgery token when I had the wrong URL, but I forgot to retest that when I had the correct one.
1.Remove the
@Html.AntiForgeryToken()
inside your form,like below:Then after you serialize the form you can get the AntiForgeryToken, like below:
Because when you don’t add
@Html.AntiForgeryToken()
inside form, after you serialize the form you don’t get the AntiForgeryToken, like below:Besides, if you use
<form asp-action="Add" >
In ASP.Net Core anti forgery token is automatically added to forms, so you don’t need to add@Html.AntiForgeryToken()
,you can find in the below :2.change your ajax like below:
result: