I have a problem with passing data from view to controller... When I was clicked button which sending POST - I have got only data for Category.Name. No subcategories, no ids etc. I am thinking I do something wrong with my view but i am not sure...
I need really help. Thanks for everything comments.
That is my View:
#model AplikacjaFryzjer_v2.Models.Category
#{
ViewData["Title"] = "Edytuj kategorię";
Layout = "~/Views/Shared/_Layout.cshtml";
var SubcategoriesData = (IList<AplikacjaFryzjer_v2.Models.Subcategory>)ViewBag.Subcategories;
}
<h1>Edytuj kategorię</h1>
<form method="post">
<div class="form-group row">
<div class="col">
<div asp-validation-summary="All" class="text-danger"></div>
<div class="form-group">
<label asp-for="Name" class="col-sm-10 col-form-label"></label>
<div class="col-sm-10">
<input asp-for="Name" disabled class="form-control" />
</div>
<span asp-validation-for="Name" class="text-danger"></span>
</div>
<button class="btn btn-primary" type="submit" id="update">Aktualizuj kategorię</button>
</div>
<div class="col">
#if (SubcategoriesData != null)
{
<div class="col-sm-10 col-form-label">
<div id="subcatContainer">
#foreach (var subcategory in SubcategoriesData.ToList())
{
<div class="form-group col-sm-6">
<input asp-for="#subcategory.Name" />
<button class="btn btn-danger" type="button" id="remove">Usuń</button>
<span asp-validation-for="#subcategory.Name" class="text-danger"></span>
</div>
}
</div>
<button type="button" class="btn btn-secondary" id="add">Dodaj podkategorię</button>
</div>
}
else
{
<div id="container" class="col-md-6">
<label id="labelName">Nazwa podkategorii</label>
<input id="inputName" />
<button type="button" class="btn btn-secondary" id="addNew">Dodaj</button>
</div>
}
</div>
</div>
</form>
<script>
$(document).ready(function (e) {
// Variables
var i = #SubcategoriesData.Count()-1;
// Add rows to the form
$("#add").click(function (e) {
var html = '<p /><div class="form-group col-sm-6"><input asp-for="Subcategories[' + i + '].Name" /><button class="btn btn-danger" type="button" id="remove">Usuń</button></div>';
i++;
$("#subcatContainer").append(html).before();
});
// Remove rows from the form
$("#subcatContainer").on('click', '#remove', function (e) {
i--;
$(this).parent('div').remove();
});
// Populate values from the first row
});
</script>
My Actions EditCategory in controller:
[HttpGet]
public ViewResult EditCategory(int Id)
{
var category = _categoriesRepository.GetCategory(Id);
if (category == null)
{
ViewBag.ErrorMessage = $"Kategoria o id = {Id} nie została odnaleziona";
return View("NotFound");
}
ViewBag.Subcategories = category.Subcategories;
return View(category);
}
[HttpPost]
public IActionResult EditCategory(Category category)
{
if (!ModelState.IsValid)
{
// store Subcategories data which has been added
ViewBag.Subcategories = category.Subcategories == null ? new List<Subcategory>() { } : category.Subcategories;
return View("EditCategory");
}
_categoriesRepository.UpdateCategory(category);
return RedirectToAction("ManageCategories");
}
And my object (model):
public class Category
{
public int Id { get; set; }
public string Name { get; set; }
public List<Subcategory> Subcategories {get;set;}
}
I have got only data for Category.Name. No subcategories, no ids etc.
Based on your Category model class, the property Subcategories is defined as List<Subcategory>, to make form data values that browser user post could be automatically bound to this property, you can modify the field of Subcategories related to <input asp-for="#Subcategories[i].Name" /> as below.
#model AplikacjaFryzjer_v2.Models.Category
#{
ViewData["Title"] = "Edytuj kategorię";
Layout = "~/Views/Shared/_Layout.cshtml";
var Subcategories = (IList<AplikacjaFryzjer_v2.Models.Subcategory>)ViewBag.Subcategories;
}
<form method="post">
<div class="form-group row">
#*code for other fields*#
<div class="col">
#if (Subcategories != null)
{
<div class="col-sm-10 col-form-label">
<div id="subcatContainer">
#for (int i = 0; i < Subcategories.Count; i++)
{
<div class="form-group col-sm-6">
<input asp-for="#Subcategories[i].Name" />
<button class="btn btn-danger" type="button" id="remove">Usuń</button>
<span asp-validation-for="#Subcategories[i].Name" class="text-danger"></span>
</div>
}
</div>
<button type="button" class="btn btn-secondary" id="add">Dodaj podkategorię</button>
</div>
}
else
{
<div id="container" class="col-md-6">
<label id="labelName">Nazwa podkategorii</label>
<input id="inputName" />
<button type="button" class="btn btn-secondary" id="addNew">Dodaj</button>
</div>
}
</div>
</div>
</form>
Update:
why new inputs added by jquery not sending to my controller? I have got "" in my code jquery
As I mentioned in comment, please not use tag helper syntax on js client. You can try to manually set name and value attribute for new generated input field(s)
like below.
$(document).ready(function (e) {
// Variables
var i = #Subcategories.Count();
// Add rows to the form
$("#add").click(function (e) {
//var html = '<p /><div class="form-group col-sm-6"><input asp-for="Subcategories[' + i + '].Name" /><button class="btn btn-danger" type="button" id="remove">Usuń</button></div>';
var html = '<p /><div class="form-group col-sm-6"><input name="Subcategories[' + i + '].Name" value="" /><button class="btn btn-danger" type="button" id="remove">Usuń</button></div>';
i++;
$("#subcatContainer").append(html).before();
});
// Remove rows from the form
$("#subcatContainer").on('click', '#remove', function (e) {
i--;
$(this).parent('div').remove();
});
// Populate values from the first row
});
Test Result
Related
I am working on a website where I need to set the ApplicationStartDate & ApplicationEndDate. When I perform this operation, ApplicationStartDate displays correctly but ApplicationEndDate displays the value of previous record which should not be the case.
Here is the .cshtml file :
#model Derawala.Models.ViewModels.ParentForApply
#{
ViewData["Title"] = "Set Application Period";
Layout = "_Layout";
}
<h1 class="text-success mt-3"><i class="fas fa-calendar-week"></i> Set Date Range For Scholarship Acceptance :</h1>
<hr class="mx-n3" />
#if (ViewBag.IsDurationSet)
{
<div class="alert alert-success alert-dismissible fade show" role="alert">
<strong><i class="fas fa-check-circle"></i> Success!</strong> Application Acceptance Is Set From <b>#WC.AppStartDate.ToString("MMMM dd yyyy")</b> To <b>#WC.AppEndDate.ToString("MMMM dd yyyy")</b>
<button type="button" class="btn-close" data-bs-dismiss="alert" aria-label="Close"></button>
</div>
}
#if (WC.AppStartDate == DateTime.MinValue || WC.AppEndDate == DateTime.MinValue)
{
<form method="post">
<div class="row">
<div class="col-md-2">
<h4 class="text-primary p-2"><i class="fas fa-hand-point-right"></i> Start Date :</h4>
</div>
<div class="col-md-4">
<input type="date" asp-for="#Model.AppPeriod.AppStartDate" class="form-control form-control-lg" required />
</div>
<div class="text-primary col-md-2">
<h4 class="p-2"><i class="fas fa-hand-point-right"></i> End Date :</h4>
</div>
<div class="col-md-4">
<input type="date" asp-for="#Model.AppPeriod.AppEndDate" class="form-control form-control-lg" required />
</div>
</div>
<div class="row d-flex justify-content-center mt-3">
<div class="col-md-2">
<button type="submit" style="font-weight:bolder;" class="btn btn-success w-100 text-white mt-1">Set Duration <i class="fas fa-calendar-check"></i></button>
</div>
<div class="col-md-2">
<button type="reset" style="font-weight:bolder;" class="btn btn-warning w-100 mt-1">Reset Date <i class="fas fa-calendar"></i></button>
</div>
</div>
</form>
}
else
{
<h3 class="text-primary"><u>Currently Set As</u> : </h3>
<div class="row">
<div class="col-md-2">
<h4 class="text-danger p-2"><i class="fas fa-hand-point-right"></i> <u>Start</u> <u>Date</u> :</h4>
</div>
<div class="col-md-4">
<h4 class="p-2">#WC.AppStartDate.ToString("dd-MM-yyyy")</h4>
</div>
<div class="col-md-2">
<h4 class="text-danger p-2"> <i class="fas fa-hand-point-right"></i> <u>End</u> <u>Date</u> :</h4>
</div>
<div class="col-md-4">
<h4 class="p-2">#WC.AppEndDate.ToString("dd-MM-yyyy")</h4>
</div>
</div>
<br /><br />
<form method="post">
<div class="row">
<div class="col-md-2">
<h4 class="text-primary p-2"><i class="fas fa-hand-point-right"></i> Start Date :</h4>
</div>
<div class="col-md-4">
<input type="date" asp-for="#Model.AppPeriod.AppStartDate" class="form-control form-control-lg" required />
</div>
<div class="text-primary col-md-2">
<h4 class="p-2"><i class="fas fa-hand-point-right"></i> End Date :</h4>
</div>
<div class="col-md-4">
<input type="date" asp-for="#Model.AppPeriod.AppEndDate" class="form-control form-control-lg" required />
</div>
</div>
<div class="row d-flex justify-content-center mt-3">
<div class="col-md-2">
<button type="submit" style="font-weight:bolder;" class="btn btn-success w-100 text-white mt-1">Set Duration <i class="fas fa-calendar-check"></i></button>
</div>
<div class="col-md-2">
<button type="reset" style="font-weight:bolder;" class="btn btn-warning w-100 mt-1">Reset Date <i class="fas fa-calendar"></i></button>
</div>
</div>
</form>
}
[HttpGet] Controller Method :
[HttpGet]
public async Task <IActionResult> AppPeriod(bool IsSuccess=false)
{
ParentForApply ParentVM = new ParentForApply();
int count = await _db.AppDuration.CountAsync();
if (count == 0)
{
WC.AppStartDate = new DateTime();
WC.AppEndDate = new DateTime();
}
else
{
WC.AppStartDate = await _db.AppDuration.MaxAsync(i => i.AppStartDate);
WC.AppEndDate = await _db.AppDuration.MaxAsync(i => i.AppEndDate);
}
ViewBag.IsDurationSet = IsSuccess;
return View();
}
[HttpPost] Controller Method :
[HttpPost]
[ValidateAntiForgeryToken]
public async Task<IActionResult> AppPeriod(ParentForApply ParentVM)
{
int id = await _db.AppDuration.MaxAsync(i => i.Id);
var data = await _db.AppDuration.FindAsync(id);
_db.AppDuration.Remove(data);
AppDurationPeriod app = new AppDurationPeriod()
{
AppStartDate = ParentVM.AppPeriod.AppStartDate,
AppEndDate = ParentVM.AppPeriod.AppEndDate
};
WC.AppStartDate = app.AppStartDate;
WC.AppEndDate = app.AppEndDate;
await _db.AppDuration.AddAsync(app);
await _db.SaveChangesAsync();
return RedirectToAction("AppPeriod",new { IsSuccess = true});
}
I am deleting the last inserted record and inserting new record in the table to use as the latest dates.
It can be seen in the images that, database has stored the correct values but website doesn't show the same value.
In the second line of else block of the last image, something phishy happenes when I debug the code. Second line of that else block somehow changes the value of AppEndDate from the original value to 30-06-2022
This is because when you load the page, the largest data is fetched from the database table by default, you can change the HttpGet method you use to get the data like this:
[HttpGet]
public async Task<IActionResult> AppPeriod(bool IsSuccess = false)
{
ParentForApply ParentVM = new ParentForApply();
int count = await _db.AppDuration.CountAsync();
if (count == 0)
{
WC.AppStartDate = new DateTime();
WC.AppEndDate = new DateTime();
}
else
{
int id = await _db.AppDuration.MaxAsync(i => i.Id);
var data = await _db.AppDuration.FindAsync(id);
WC.AppStartDate = data.AppStartDate;
WC.AppEndDate = data.AppEndDate;
//WC.AppStartDate = await _db.AppDuration.MaxAsync(i => i.AppStartDate);
//WC.AppEndDate = await _db.AppDuration.MaxAsync(i => i.AppEndDate);
}
ViewBag.IsDurationSet = true;
return View();
}
Test Result:
I'm facing an odd issue here.
I have a page where i have setup a PageRemote attribute to validate a field, and on the same page, i have 2 buttons that each call a distinct handler using the asp-page-handler property (1 to update the content, the other to delete it).
If i remove the PageRemote validation, the handlers for both buttons are triggered as expected, but when i leave the PageRemote validation on the page, the buttons specific handlers are not called, although the PageRemote handler is correctly triggered.
Furthermore, when leaving the PageRemote validation on the page, if i force its validation to return false, then afterwards the buttons trigger their respective handler, but if i do not force it, then the behaviour is as described earlier, where the handlers are not triggered.
Can someone explain me if there is a catch on using these two things on the same page, and/or how to overcome this?
Below is a sample of the page code:
public class EditModel : PageModel
{
private IConfiguration _configuration;
[Required(ErrorMessageResourceType = typeof(ErrorMessages),
ErrorMessageResourceName = nameof(ErrorMessages.SlugRequired))]
[MinLength(3, ErrorMessageResourceType = typeof(ErrorMessages),
ErrorMessageResourceName = nameof(ErrorMessages.SlugMinLength))]
[MaxLength(128, ErrorMessageResourceType = typeof(ErrorMessages),
ErrorMessageResourceName = nameof(ErrorMessages.SlugMaxLength))]
[RegularExpression(#"^[0-9a-zA-Z_/-]*$", ErrorMessageResourceType = typeof(ErrorMessages),
ErrorMessageResourceName = nameof(ErrorMessages.SlugAllowedCharacters))]
[PageRemote(ErrorMessageResourceType = typeof(ErrorMessages),
ErrorMessageResourceName = nameof(ErrorMessages.SlugDuplicate),
AdditionalFields = "__RequestVerificationToken,GenericContentDTO.GenericContent.GenericContentId",
HttpMethod = "post",
PageHandler = "CheckSlug")]
[Display(Name = "URL Title")]
[BindProperty]
public string Slug { get; set; }
[TempData]
public string FormResultMessage { get; set; }
[BindProperty]
public GenericContentDTO GenericContentDTO { get; set; }
public EditModel(IConfiguration configuration)
{
_configuration = configuration;
}
public IActionResult OnGet(Guid genericContentId)
{
if (genericContentId.ToString() == "")
{
return NotFound();
}
...
Code to load content
...
return Page();
}
public async Task<IActionResult> OnPostUpdate()
{
if (!ModelState.IsValid)
{
return Page();
}
...
Code to update content
...
return RedirectToPage(new { GenericContentId = GenericContentDTO.GenericContent.GenericContentId });
}
public IActionResult OnPostDelete()
{
...
Code to delete content
}
public JsonResult OnPostCheckSlug()
{
var token = HttpContext.Session.GetString("APIAuthorizationToken");
CheckSlugDTO CheckSlug = new CheckSlugDTO
{
Slug = Slug,
ContentId = GenericContentDTO.GenericContent.GenericContentId,
Exists = true
};
CheckSlug = APICommunicationHelper.PostData<CheckSlugDTO>(CheckSlug, _configuration["AppConfigs:APIAddress"] + "api/CheckGenericContentSlugExistance", token);
return new JsonResult(!CheckSlug.Exists);
}
}
And of the Razor Code:
#page "{GenericContentId:Guid}"
#model MyProject.Pages.Generic_Contents.EditModel
#{
}
<form method="post" id="editForm" name="editForm" enctype="multipart/form-data">
<h3>#TempData["FormResultMessage"]</h3>
<ul class="nav nav-tabs">
<li class="nav-item"><a class="nav-link active" data-toggle="tab" href="#main">Main</a></li>
<li class="nav-item"><a class="nav-link" data-toggle="tab" href="#meta">Meta</a></li>
</ul>
<div class="tab-content">
<div id="main" class="tab-pane active">
<br />
<div asp-validation-summary="ModelOnly" class="text-danger"></div>
#Html.HiddenFor(model => model.GenericContentDTO.GenericContent.GenericContentId)
<div class="form-group">
<label asp-for="GenericContentDTO.GenericContent.Title" class="control-label"></label>
<input asp-for="GenericContentDTO.GenericContent.Title" class="form-control" />
<span asp-validation-for="GenericContentDTO.GenericContent.Title" class="text-danger"></span>
</div>
<div class="form-group">
<label asp-for="Slug" class="control-label"></label>
<input asp-for="Slug" class="form-control" />
<span asp-validation-for="Slug" class="text-danger"></span>
</div>
<div class="form-group row">
<div class="col-4">
<label asp-for="GenericContentDTO.MainImage" class="control-label"></label>
<input asp-for="GenericContentDTO.MainImage" type="file" class="form-control" />
</div>
</div>
<div class="form-group">
<label asp-for="GenericContentDTO.GenericContent.Summary" class="control-label"></label>
#Html.TextAreaFor(model => model.GenericContentDTO.GenericContent.Summary, new { #class = "form-control", #rows = 5 })
<span asp-validation-for="GenericContentDTO.GenericContent.Summary" class="text-danger"></span>
</div>
<div class="form-group">
<label asp-for="GenericContentDTO.GenericContent.ContentText" class="control-label"></label>
#Html.TextAreaFor(model => model.GenericContentDTO.GenericContent.ContentText, new { #class = "form-control editorHtml" })
</div>
<div class="form-group">
<label asp-for="GenericContentDTO.GenericContent.IsActive" class="control-label"></label>
#Html.CheckBoxFor(model => model.GenericContentDTO.GenericContent.IsActive)
</div>
</div>
<div id="meta" class="tab-pane fade">
<div class="form-group">
<label asp-for="GenericContentDTO.GenericContent.MetaDescription" class="control-label"></label>
#Html.TextAreaFor(model => model.GenericContentDTO.GenericContent.MetaDescription, new { #class = "form-control", #rows = 5 })
<span asp-validation-for="GenericContentDTO.GenericContent.MetaDescription" class="text-danger"></span>
</div>
<div class="form-group">
<label asp-for="GenericContentDTO.GenericContent.MetaKeywords" class="control-label"></label>
#Html.TextAreaFor(model => model.GenericContentDTO.GenericContent.MetaKeywords, new { #class = "form-control", #rows = 5 })
<span asp-validation-for="GenericContentDTO.GenericContent.MetaKeywords" class="text-danger"></span>
</div>
</div>
<div class="form-group text-right">
<a asp-area="" asp-page="/Generic-Contents" class="btn btn-secondary">Cancel</a>
<button type="submit" class="btn btn-danger" asp-page-handler="Delete">Delete Content</button>
<button type="submit" class="btn btn-primary" asp-page-handler="Update">Update Content</button>
</div>
</div>
</form>
#section Scripts {
#{await Html.RenderPartialAsync("_ValidationScriptsPartial");}
}
Thanks
I use Modal and Load Partial view to it, but if I keep fields blank no validation happened and modal closed after click submit button.
Also I use Required annotation in my viewmodel. Also when I click submit it calls action direct in controller.
My Question: how can I display a validation message in modal form?
#section scripts{
<script>
function onFailureDefault(data) {
$("#AddOrderDetailModalDiv").valid()
}
function OpenAddOrderDetailTempItemOnSuccess() {
$("#AddOrderDetailModalDiv").modal("show");
}
function AddOrderDetailTempItemOnComplete() {
$("#AddOrderDetailModalDiv").modal("hide");
}
</script>
}
#model OrderDetailViewModel
#using (Html.BeginForm("AddOrderDetailTempItem", "Orders", FormMethod.Post, new
{
id = "AddForm",
#data_ajax = "true",
#data_ajax_method = "post",
#data_ajax_update = "#OrderDetailList",
#data_ajax_failure = "onFailureDefault",
#data_ajax_complete = "AddOrderDetailTempItemOnComplete"
}))
{
<div class="modal-dialog modal-dialog-centered modal-dialog-scrollable modal-lg" role="document">
<div class="modal-content">
<div class="modal-header bg-warning white">
<h5 class="modal-title" id="exampleModalCenterTitle">#( Model.ID > 0 ? "Edit Product" : "Add Product" )</h5>
<button type="button" class="close" data-dismiss="modal" aria-label="Close">
<span aria-hidden="true">×</span>
</button>
</div>
<div class="modal-body">
<div>
#Html.HiddenFor(m => m.ID)
<div asp-validation-summary="All" class="text-danger"></div>
<div class="row">
<div class="col-sm-6">
<div class="form-group">
<label asp-for="ProductId" class="control-label"></label>
#Html.DropDownListFor(m => m.ProductId, Model.ProductsList, " ", htmlAttributes: new { #class = "select2 form-control" })
<span asp-validation-for="ProductId" class="text-danger"></span>
</div>
</div>
<div class="col-sm-6">
<div class="form-group">
<label asp-for="Quantity" class="control-label"></label>
<input asp-for="Quantity" required class="form-control" />
</div>
</div>
<div class="col-sm-6">
<div class="form-group">
<label asp-for="Unit" class="control-label"></label>
#Html.DropDownListFor(m => m.Unit, Model.QuantityUnitsList, " ", htmlAttributes: new { #class = "form-control" })
<span asp-validation-for="Unit" class="text-danger"></span>
</div>
</div>
<div class="col-sm-6">
<div class="form-group">
<label asp-for="UnitPrice" class="control-label"></label>
<input asp-for="UnitPrice" class="form-control" />
</div>
</div>
<label id="ErrorMessage" asp-for="ErrorMessage" class="form-control" />
</div>
</div>
</div>
<div class="modal-footer">
<input type="submit" value="Add Product" id="postSave" class="btn btn-primary" />
<button type="button" class="btn btn-secondary" data-dismiss="modal">Close</button>
</div>
</div>
</div>
}
[HttpPost]
public ActionResult AddOrderDetailTempItem(OrderDetailViewModel model)
{
if (!ModelState.IsValid)
{
return View(model);
}
List<OrderDetailViewModel> models = OrderDetailViewModelList;
var product = productService.SingleBy(model.ProductId);
if (model.ID > 0)
{
var updatedItem = models.Find(m => m.ID == model.ID);
updatedItem.Quantity = model.Quantity;
updatedItem.ProductId = model.ProductId;
updatedItem.UnitPrice = model.UnitPrice;
updatedItem.TotalPrice = model.Quantity * model.UnitPrice;
updatedItem.ProductName = product.Name;
updatedItem.Unit = model.Unit;
updatedItem.QuantityUnitsText = ((QuantityUnits)model.Unit).ToString();
updatedItem.isActive = true;
//mapper.Map(model,updatedItem);///
}
else
{
models.Add(new OrderDetailViewModel
{
ID = counter - 1,//models.Count + 1,
Quantity = model.Quantity,
ProductId = model.ProductId,
UnitPrice = model.UnitPrice,
TotalPrice = model.Quantity * model.UnitPrice,
ProductName = product.Name,
Unit = model.Unit,
QuantityUnitsText = ((QuantityUnits)model.Unit).ToString(),
isActive = true,
});
counter -= 1;
}
OrderDetailViewModelList = models;
return PartialView("_OrderDetailGridPartial", OrderDetailViewModelList.Where(a => a.isActive == true).ToList());
}
Parent View
#using (Html.BeginForm("AddOrder", "Orders", FormMethod.Post, new
{
id = "AddForm",
#data_ajax = "true",
#data_ajax_method = "post",
//#data_ajax_update = "#OrderDetailList",
#data_ajax_complete = "AddOrderOnComplete"
}))
{
<div asp-validation-summary="ModelOnly" class="text-danger"></div>
<div class="row">
<div class="col-sm-6">
<div class="form-group">
<label asp-for="DeliveryDate" class="control-label"></label>
<input asp-for="DeliveryDate" class="form-control" type="date" />
<span asp-validation-for="DeliveryDate" class="text-danger"></span>
</div>
</div>
<div class="col-sm-6">
<div class="form-group">
<label asp-for="OrderDate" class="control-label"></label>
<input asp-for="OrderDate" class="form-control" disabled type="date" />
<span asp-validation-for="OrderDate" class="text-danger"></span>
</div>
</div>
</div>
<div class="row">
<div class="col-sm-6">
<div class="form-group">
<label asp-for="CustomerId" class="control-label"></label>
#Html.DropDownListFor(m => m.CustomerId, Model.CustomersList, "Please select", htmlAttributes: new { #class = "select2 form-control" })
<span asp-validation-for="CustomerId" class="text-danger"></span>
</div>
</div>
<div class="col-sm-6">
<div class="form-group">
<label asp-for="Notes" class="control-label"></label>
<textarea asp-for="Notes" rows="4" class="form-control"></textarea>
<span asp-validation-for="Notes" class="text-danger"></span>
</div>
</div>
</div>
<div class="content-header row">
<div class="content-header-left col-md-9 col-12 mb-2">
</div>
<div class="content-header-right text-md-right col-md-3 col-12">
<div class="form-group breadcrum-right">
<button type="button" class="btn bg-gradient-danger mr-1 mb-1 waves-effect waves-light">
<i class="feather icon-package">
#Html.ActionLink("Add Product", "AddOrderDetailTempItem", "Orders", routeValues: null, htmlAttributes: new
{
Style = "color:White;font-family:'Montserrat';padding-left: 10px;",
#data_ajax = "true",
#data_ajax_method = "Get",
#data_ajax_update = "#AddOrderDetailModalDiv",
#data_ajax_failure = "onFailureDefault",
#data_ajax_success = "OpenAddOrderDetailTempItemOnSuccess",
})
</i>
</button>
</div>
</div>
</div>
<div id="OrderDetailList">
<partial name="_OrderDetailGridPartial.cshtml" model="Model.OrderDetailViewModel" />
</div>
<div class="form-group col-sm-3">
<input type="submit" name="btn" value="Save" class="btn btn-primary" />
</div>
}
My Model
public class OrderDetailViewModel
{
public int ID { get; set; }
public int OrderId { get; set; }
[Required(ErrorMessage = "حقل إجباري")]
[Display(Name ="Product Name")]
public int ProductId { get; set; }
public string ProductName { get; set; }
[Required(ErrorMessage = "حقل إجباري")]
public int Unit { get; set; }
[Required(ErrorMessage = "حقل إجباري")]
public int Quantity { get; set; }
[Required(ErrorMessage = "حقل إجباري")]
public decimal UnitPrice { get; set; }
public decimal TotalPrice { get; set; }
public SelectList ProductsList { get; set; }
public SelectList QuantityUnitsList { get; set; }
public bool isActive { get; set; }
public string QuantityUnitsText { get; set; }
public string ErrorMessage { get; set; }
}
Your code is not complete,so I provide a work demo,you can check it.
Model:
public class Student
{
public int Id { get; set; }
[Required]
public string Name { get; set; }
}
_OrderDetailGridPartial:
#model Student
<div id="MyModal" class="modal fade" role="dialog">
<div class="modal-dialog modal-lg">
<div class="modal-content">
<div class="modal-header" >
<h4 class="modal-title" >Update Role</h4>
</div>
<div class="modal-body">
<form id="myform" method="post">
<div>
<label>Id</label>
<input asp-for="Id" />
<span asp-validation-for="Id" class="text-danger"></span>
</div>
<div>
<label>Name</label>
<input asp-for="Name" />
<span asp-validation-for="Name" class="text-danger"></span>
</div>
<button id="button" class="btn btn-default">Save</button>
</form>
</div>
<div class="modal-footer">
<button type="button" class="btn btn-default" data-dismiss="modal">Close</button>
</div>
</div>
</div>
</div>
Index View:
<button id="showmodal" class="btn btn-danger">
Click
</button>
<div id="partical">
<partial name="~/Views/Shared/_OrderDetailGridPartial.cshtml" />
</div>
#section scripts{
<script>
$("#showmodal").click(function () {
$('#MyModal').modal('show');
})
$("#button").click(function (e) {
e.preventDefault();
var model = $('#myform').serialize();
console.log(model);
$.ajax({
type: 'POST',
url: 'home/index',
async: false,
contentType: "application/x-www-form-urlencoded; charset=utf-8",
data: model,
success: function (result) {
$('#partical').html(result);
$('#MyModal').modal('show');
}
});
})
</script>
}
Action:
public IActionResult Index()
{
return View();
}
[HttpPost]
public IActionResult Index(Student student)
{
if (!ModelState.IsValid)
{
return PartialView("_OrderDetailGridPartial",student);
}
return View();
}
Test result
Technology Info:
Framework = Asp.Net Core 3.1
IDE = VisualStudio 2019
Problem:
I have a controller with Update and Delete Action Methods. I have UpdateView and DeleteView from where I need to redirect to the respective controller. I have implemented a button that can submit the form. Still I'm facing HTTP ERROR 405 Issues with PUT & DELETE. Can somebody help me to resolve this issue. Thanks in advance
Controller:
[HttpPut]
[ActionName("ModifyEmployee")]
public IActionResult ModifyEmployee(int employeeId, Malips.Data.Employee employee)
{
if (ModelState.IsValid)
{
Malips.Data.Employee employeeDetail = _hrService.EmployeeSystem.UpdateEmployee(employee);
return View("GetEmployee", employeeDetail);
}
return View();
}
[HttpDelete]
public IActionResult DeleteEmployee(int employeeId)
{
_hrService.EmployeeSystem.DeleteEmployee(employeeId);
return View("Index");
}
UpdateView:
#model Employee
#{
ViewBag.Title = "Modify Employee";
}
<div>
<form asp-controller="Hr" asp-action="ModifyEmployee" asp-route-employeeId="#Model.EmpId">
<div class="form-group">
<div asp-validation-summary="All" class="text-danger">
</div>
</div>
#Html.HiddenFor(e => e.EmpId)
<div class="form-group row">
<label asp-for="FirstName" class="col-sm-2">First Name</label>
<input asp-for="FirstName" class="col-sm-10" />
<span asp-validation-for="FirstName" class="text-danger"></span>
</div>
<button type="submit" class="btn btn-info">Update</button>
</form>
</div>
DeleteView:
<form asp-controller="Hr" asp-action="DeleteEmployee" asp-route-employeeId="#Model.EmpId">
<div class="row card" style="width: 18rem;">
<div class="card-body">
<label hidden="hidden">#Model.EmpId</label>
<h5 class="card-title">#Model.FirstName #Model.LastName</h5>
<p class="card-text">#Model.Salary </p>
<button type="submit" class="btn btn-danger">Delete</button>
</div>
</div>
</form>
The current HTML5 does not support PUT or DELETE in forms. You can use it with ajax or httpclient only. Or you can try #Html.BeginForm razor page template if it is possible. #Html.BeginForm has post metod choice.
For now remove [ActionName("ModifyEmployee")], [httpput] and [httpdelete] from your action attributes.
And change
public IActionResult ModifyEmployee(int employeeId, Malips.Data.Employee employee)
to:
public IActionResult ModifyEmployee(Employee employee)
since you don't use and don't need emploeeId. And remove asp-route-employeeId="#Model.EmpId" from ModifyEmployee view too.
Like #Sergey said,You can use it with ajax.Below is a working demo.
UpdateView:
<div>
<form id="update" asp-controller="Hr" asp-action="ModifyEmployee">
<div class="form-group">
<div asp-validation-summary="All" class="text-danger">
</div>
</div>
#Html.HiddenFor(e => e.EmpId)
<div class="form-group row">
<label asp-for="FirstName" class="col-sm-2">First Name</label>
<input asp-for="FirstName" class="col-sm-10" />
<span asp-validation-for="FirstName" class="text-danger"></span>
</div>
<div class="form-group row">
<label asp-for="LastName" class="col-sm-2">First Name</label>
<input asp-for="LastName" class="col-sm-10" />
<span asp-validation-for="LastName" class="text-danger"></span>
</div>
<button type="submit" id="submit" class="btn btn-info">Update</button>
</form>
</div>
#section scripts
{
<script>
$("#submit").click(function (e) {
e.preventDefault();
var data = $('#update').serialize();
$.ajax({
type: "PUT",
url: "/hr/Modifyemployee",
data: data,
success: function (response) {
window.location.href = response.redirectToUrl;
}
});
})
</script>
}
ModifyEmployee Action
[HttpPut]
[ActionName("ModifyEmployee")]
//remember add this.
[ValidateAntiForgeryToken]
public async Task<IActionResult> ModifyEmployee(Employee employee)
{
//....
return new JsonResult(new { redirectToUrl = Url.Action("Index", "Hr") });
}
DeleteView:
<div>
<form id="delete" asp-controller="Hr" asp-action="DeleteEmployee" asp-route-employeeId="#Model.EmpId">
<div class="row card" style="width: 18rem;">
<div class="card-body">
<label hidden="hidden">#Model.EmpId</label>
<h5 class="card-title">#Model.FirstName #Model.LastName</h5>
<button type="submit" id="submit" class="btn btn-danger">Delete</button>
</div>
</div>
</form>
</div>
#section scripts
{
$("#submit").click(function (e) {
e.preventDefault();
$.ajax({
type: "delete",
url: "/hr/DeleteEmployee?id=" + #Model.EmpId,
success: function (response) {
window.location.href = response.redirectToUrl;
}
});
})
</script>
}
DeleteEmployee Action
[HttpDelete]
public async Task<IActionResult> DeleteEmployee(int id)
{
//......
return new JsonResult(new { redirectToUrl = Url.Action("Index", "hr") });
}
Test Result:
I have a modal that returns login view . I want to check if user does not exist return the view with some error . I tried using
ModelState.AddModelError()
But the modal close and view is opened.
this is my code:
public IActionResult Login(LoginViewModel login)
{
if (!ModelState.IsValid)
return View();
var user = _userServies.getUserByEmailandPass(login.Email, login.Password);
if (user == null)
{
ModelState.AddModelError("Email","email or password is wrong");
return view();
}
return Redirect("/");
}
Login modal form data via ajax in ASP.NET Core 3.1
Use jQuery to send ajax and perform modal actions dynamically.
Here are codes of controller.
[HttpPost]
public IActionResult Login(LoginViewModel login)
{
if (ModelState.IsValid)
{
//var user = _userServies.getUserByEmailandPass(login.Email, login.Password);
//if (user == null)
if (login.Email.Equals(login.Password))
{
ModelState.AddModelError("Email", "email or password is wrong");
}
}else
ModelState.AddModelError("Email", "email or password invalid");
return PartialView("_LoginModalPartial", login);
}
Here are codes of _LoginModalPartial.cshtml.
#model LoginViewModel
#{
Layout = "_Layout";
}
<button type="button" class="btn btn-primary" data-toggle="modal" data-target="#login">
Login
</button>
<div id="modal-placeholder">
<!-- Modal -->
<div class="modal fade" id="login" tabindex="-1" role="dialog" aria-labelledby="addContactLabel" aria-hidden="true">
<div class="modal-dialog" role="document">
<div class="modal-content">
<div class="modal-header">
<h5 class="modal-title" id="addContactLabel">Login</h5>
<button type="button" class="close" data-dismiss="modal" aria-label="Close">
<span aria-hidden="true">×</span>
</button>
</div>
<div class="modal-body">
<form asp-action="Login">
<input name="IsValid" type="hidden" value="#ViewData.ModelState.IsValid.ToString()" />
<div class="form-group">
<label asp-for="Email"></label>
<input asp-for="Email" class="form-control" />
<span asp-validation-for="Email" class="text-danger"></span>
</div>
<div class="form-group">
<label asp-for="Password"></label>
<input asp-for="Password" class="form-control" />
<span asp-validation-for="Password" class="text-danger"></span>
</div>
</form>
</div>
<div class="modal-footer">
<button type="button" class="btn btn-secondary" data-dismiss="modal">Close</button>
<button type="button" class="btn btn-primary" data-save="modal">Login</button>
</div>
</div>
</div>
</div>
</div>
<script
src="https://code.jquery.com/jquery-3.5.1.min.js"
integrity="sha256-9/aliU8dGd2tb6OSsuzixeV4y/faTqgFtohetphbbj0="
crossorigin="anonymous"></script>
<script>
$(function () {
$('button[data-save="modal"]').click(function (event) {
var form = $(this).parents('.modal').find('form');
var actionUrl = form.attr('action');
var dataToSend = form.serialize();
$.post(actionUrl, dataToSend).done(function (data) {
var placeholderElement = $('#modal-placeholder');
var newBody = $('.modal-body', data);
// find IsValid input field and check it's value
// if it's valid then hide modal window
var isValid = newBody.find('[name="IsValid"]').val() == 'True';
if (isValid) {
placeholderElement.find('.modal').modal('hide');
location.href = "/";
} else {
placeholderElement.find('.modal-body').replaceWith(newBody);
}
});
});
});
</script>
You should use javascript (do a post request) to send the form to the Login post action. On the success of the ajax call you need to replace the content of your modal with the partialview (=data) that your action will return
$.ajax({
type: 'POST',
url: url to your action,
data: new FormData($("#modal_form")[0]),
success: function (data) {
$("#site_modal").html(data);
}
});
In the login method change the return View(); with return PartialView();. The partialview will only return the html of the action (=excluding the layout page that will be added when using View())