Dropdowns blank when rendered as partial view - .net-core

I am attempting to load a modal create form via the method OnGetCertificationPartial. The form is loading, however the dropdowns are blank.
The dropdowns are not blank when loading the /Create page via the OnGet method
How can I get the dropdowns to populate when loaded as a partial via OnGetCertificationPartial method?
Create.cshtml.cs
using System.Linq;
using System.Threading.Tasks;
using Microsoft.AspNetCore.Mvc;
using Microsoft.AspNetCore.Mvc.RazorPages;
using Microsoft.AspNetCore.Mvc.Rendering;
using EmployeeCertification.Models.Scaffold;
namespace EmployeeCertification.Pages.CertificationRuleCertifications
{
public class CreateModel : PageModel
{
private readonly EmployeeCertification.Models.Scaffold.EmployeeCertificationDBContext _context;
public CreateModel(EmployeeCertification.Models.Scaffold.EmployeeCertificationDBContext context)
{
_context = context;
}
public IActionResult OnGet(string ruleName)
{
ViewData["CertificationId"] = new SelectList(_context.Certifications, "CertificationId", "CertificationName");
ViewData["CertificationRuleId"] = new SelectList(_context.CertificationRules.Where(i => i.RuleName == ruleName), "CertificationRuleId", "RuleName");
return Page();
}
[BindProperty]
public CertificationRuleCertification CertificationRuleCertification { get; set; }
public PartialViewResult OnGetCertificationPartial()
{
ViewData["CertificationId"] = new SelectList(_context.Certifications, "CertificationId", "CertificationName");
ViewData["CertificationRuleId"] = new SelectList(_context.CertificationRules, "CertificationRuleId", "RuleName");
return Partial("/Pages/Shared/_CertificationRuleCertification.cshtml");
}
// To protect from overposting attacks, see https://aka.ms/RazorPagesCRUD
public async Task<IActionResult> OnPostAsync()
{
if (!ModelState.IsValid)
{
return Page();
}
_context.CertificationRuleCertifications.Add(CertificationRuleCertification);
await _context.SaveChangesAsync();
return RedirectToPage("./Index");
}
}
}
Details.cshtml (the screen the user clicks on to trigger the modal)
#page
#model EmployeeCertification.Pages.CertificationRules.DetailsModel
#{
ViewData["Title"] = "Details";
}
<h1>Details</h1>
<div>
<h4>CertificationRule</h4>
<hr />
<dl class="row">
<dt class="col-sm-2">
#Html.DisplayNameFor(model => model.CertificationRule.RuleName)
</dt>
<dd class="col-sm-10">
#Html.DisplayFor(model => model.CertificationRule.RuleName)
</dd>
<dt class="col-sm-2">
#Html.DisplayNameFor(model => model.CertificationRule.AppliesToAllEmployees)
</dt>
<dd class="col-sm-10">
#Html.DisplayFor(model => model.CertificationRule.AppliesToAllEmployees)
</dd>
<dt class="col-sm-2">
#Html.DisplayNameFor(model => model.CertificationRule.Active)
</dt>
<dd class="col-sm-10">
#Html.DisplayFor(model => model.CertificationRule.Active.ActiveName)
</dd>
</dl>
</div>
<div>
<a asp-page="./Edit" asp-route-id="#Model.CertificationRule.CertificationRuleId">Edit</a> |
<a asp-page="./Index">Back to List</a>
</div>
<div>
<button class="btn btn-sm btn-dark details" data-id="#Model.CertificationRule.CertificationRuleId" data-toggle="modal" data-target="#details-modal">Details</button>
</div>
<div class="modal fade" tabindex="-1" role="dialog" id="details-modal">
<div class="modal-dialog">
<div class="modal-content">
<div class="modal-header">
<h5 class="modal-title">Product Details</h5>
<button type="button" class="close" data-dismiss="modal" aria-label="Close">
<span aria-hidden="true">×</span>
</button>
</div>
<div class="modal-body"></div>
</div>
</div>
</div>
#section scripts{
<script>
$(function () {
$('button.details').on('click', function () {
$('.modal-body').load('/certificationrulecertifications/create?handler=CertificationPartial');
});
})
</script>
}
_CertificationRuleCertification.cshtml (routed to via OnGetCertificationPartial)
#model EmployeeCertification.Pages.CertificationRuleCertifications.CreateModel
<h1>Add</h1>
<h4>Certification</h4>
<hr />
<div class="row">
<div class="col-md-4">
<form method="post">
<div asp-validation-summary="ModelOnly" class="text-danger"></div>
<div class="form-group">
<label asp-for="CertificationRuleCertification.CertificationRuleId" class="control-label"></label>
<select asp-for="CertificationRuleCertification.CertificationRuleId" class="form-control" asp-items="ViewBag.CertificationRuleId"></select>
</div>
<div class="form-group">
<label asp-for="CertificationRuleCertification.CertificationId" class="control-label"></label>
<select asp-for="CertificationRuleCertification.CertificationId" class="form-control" asp-items="ViewBag.CertificationId"></select>
</div>
<div class="form-group">
<input type="submit" value="Create" class="btn btn-primary" />
</div>
</form>
</div>
</div>
Create.cshtml (routed to via OnGet)
#page
#model EmployeeCertification.Pages.CertificationRuleCertifications.CreateModel
<h4>CertificationRuleCertification</h4>
<hr />
<div class="row">
<div class="col-md-4">
<form method="post">
<div asp-validation-summary="ModelOnly" class="text-danger"></div>
<div class="form-group">
<label asp-for="CertificationRuleCertification.CertificationRuleId" class="control-label"></label>
<select asp-for="CertificationRuleCertification.CertificationRuleId" class ="form-control" asp-items="ViewBag.CertificationRuleId"></select>
</div>
<div class="form-group">
<label asp-for="CertificationRuleCertification.CertificationId" class="control-label"></label>
<select asp-for="CertificationRuleCertification.CertificationId" class ="form-control" asp-items="ViewBag.CertificationId"></select>
</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>
#section Scripts {
#{await Html.RenderPartialAsync("_ValidationScriptsPartial");}
}

IMHO you have a bug. SelectList constructor needs an IEnumerable list as a parameter, but you use IQueryable. And create model too. You can try this
CertificationRuleCertification= new CertificationRuleCertification();
ViewData["CertificationId"] = new SelectList(_context.Certifications.ToList(), "CertificationId", "CertificationName");
ViewData["CertificationRuleId"] = new SelectList(_context.CertificationRules.ToList(), "CertificationRuleId", "RuleName");
Since you are using Razor, the code that I am suggesting should be placed not in Create page code, but in a code behind the partial page. Use OnGet or OnGetAsync for this code.
But much better variant is to use a model to keep select lists. Just add two more properties CertificationIdList and CertificationRuleIdList to the existing model.

Related

ASP.Net Core MVC CRUD PopUp Modal

I am just starting to work with ASP.Net Core MVC. I have difficulty in creating a popup modal. I've tried to create a simple page. 
Below is my model:
namespace CoreModal.Models
{
public class Employee
{
public int Id { get; set; }
public string Name { get; set; }
public string Email { get; set; }
public string Address { get; set; }
public string Phone { get; set; }
}
}
Below is my EmployeeController:
namespace CoreModal.Controllers
{
public class EmployeeController : Controller
{
public static List<Employee> empList = new List<Employee>() {
new Employee {Id=1, Name="John", Email="john#gmail.com", Address="Campbell", Phone="1234"}
};
public IActionResult Index()
{
ViewBag.Employee = empList;
return View();
}
[HttpPost]
[Route("create")]
public IActionResult Create(string name, string email, string address, string phone)
{
var newEmployee = new Employee
{
Name = name,
Email = email,
Address = address,
Phone = phone
};
empList.Add(newEmployee);
ViewBag.Employee = empList;
return RedirectToAction("Index");
}
}
}
In my Index View, I create a button to trigger a popup modal for creating a new Employee object as follow:
<i class="material-icons"></i><span>Add New Employee</span>
<d id="addEmployeeModal" class="modal fade" name="addEmployeeModal">
<div class="modal-dialog">
<div class="modal-content">
<form method="post" asp-controller="employee" asp-action="create">
<div class="modal-header">
<h4 class="modal-title">Add Employee</h4>
<button type="button" class="close" data-dismiss="modal" aria-hidden="true">×</button>
</div>
<div class="modal-body">
<div class="form-group">
<label>Name</label>
<input type="text" class="form-control" required="required" name="name"/>
</div>
<div class="form-group">
<label>Email</label>
<input type="text" class="form-control" required="required" name="email"/>
</div>
<div class="form-group">
<label>Address</label>
<input type="text" class="form-control" required="required" name="address"/>
</div>
<div class="form-group">
<label>Phone</label>
<input type="text" class="form-control" required="required" name="phone"/>
</div>
</div>
<div class="modal-footer">
<input type="button" class="btn btn-default" data-dismiss="modal" value="Cancel" />
<input type="Submit" class="btn btn-success" value="Add" />
</div>
</form>
</div>
</div>
</d>
But instead of directing to a popup modal, it directs it to url https://localhost:44330/#addEmployeeModal.
What did I do wrong?
Thanks
First of all, you should not be keeping your data inside the controller because the controller runs anew each time it is called and your data will be lost. Use a database for best results.
Your syntax for calling the modal is slightly wrong.
Check here for the correct syntax. It's not href (that's your mistake!) You can mostly copy this code and replace the inner parts with what you have.
https://getbootstrap.com/docs/4.0/components/modal/
*Note: you must be using bootstrap for this to work
Good Luck!
Edit : You can try this: (may need some tweaking)
<!-- Button trigger modal -->
<button type="button" class="btn btn-primary" data-toggle="modal" data-target="#exampleModal">
Add Employee
</button>
<!-- Modal -->
<div class="modal fade" id="exampleModal" tabindex="-1" role="dialog" aria-labelledby="exampleModalLabel" aria-hidden="true">
<div class="modal-dialog" role="document">
<div class="modal-content">
<form method="post" asp-controller="employee" asp-action="create">
<div class="modal-header">
<h5 class="modal-title" id="exampleModalLabel">Add Employee</h5>
<button type="button" class="close" data-dismiss="modal" aria-label="Close">
<span aria-hidden="true">×</span>
</button>
</div>
<div class="modal-body">
<div class="form-group">
<label>Name</label>
<input type="text" class="form-control" required="required" name="name"/>
</div>
<div class="form-group">
<label>Email</label>
<input type="text" class="form-control" required="required" name="email"/>
</div>
<div class="form-group">
<label>Address</label>
<input type="text" class="form-control" required="required" name="address"/>
</div>
<div class="form-group">
<label>Phone</label>
<input type="text" class="form-control" required="required" name="phone"/>
</div>
</div>
<div class="modal-footer">
<button type="button" class="btn btn-secondary" data-dismiss="modal">Close</button>
<input type="submit" class="btn btn-primary">Add Employee</button>
</div>
</form>
</div>
</div>
</div>
Additionally, It is better practice to send a model into the controller. Use a model on the top of your view, link it to your employee model, and send that into the controller instead.

Pass input with route id to controller method together

I want to create input with game amount. User will write how many copy of concrete game wants to buy. Then two parameters will pass to AddToCart method. First will be gameId like below (it works well) and user amount input. How to pass these two values together into controller method?
View:
#model IEnumerable
<link rel="stylesheet" href="~/css/productcards.css">
<div class="container">
<div class="row">
#foreach (var game in Model)
{
<div class="col-md-3">
<div class="product-grid">
<div class="product-image">
<a asp-controller="Game" asp-action="ShowDetails" asp-route-productId=#game.GameId>
<img class="pic-1" src="~/images/#game.ImagePath">
</a>
</div>
<div class="product-content">
<h3 class="title">
<a asp-controller="Game" asp-action="ShowDetails" asp-route-productId=#game.GameId>#game.Title</a>
</h3>
<div class="price">#game.Price.ToString() zł</div>
<a asp-controller="Cart" asp-action="AddToCart" asp-route-gameId="#game.GameId" class="btn btn-primary"><i class="fa fa-cart-plus"></i> KUP</a>
</div>
</div>
</div>
}
</div>
</div>
Controller:
public RedirectToActionResult AddToCart(int gameId)
{
var selectedGame = _appDbContext.Games.FirstOrDefault(x => x.GameId == gameId);
if(selectedGame != null)
{
_cart.AddToCart(selectedGame, 1);
}
return RedirectToAction("Index");
}
Change your view like below:
#foreach (var game in Model)
{
<form method="post">
<div class="col-md-3">
<div class="product-grid">
<div class="product-content">
<h3 class="title">
<a asp-controller="Game" asp-action="ShowDetails" asp-route-productId=#game.GameId>#game.Title</a>
</h3>
<div class="price">#game.Price.ToString() zł</div>
<div class="amount"><input name="amount" type="number" /></div> #*add this line*#
</div>
</div>
</div>
<div class="col-md-3">
#*change <a> to <input> and add a <form>*#
<input type="submit" asp-route-gameId="#game.GameId" asp-controller="Cart" asp-action="AddToCart" class="btn btn-primary" value="KUP"/>
</div>
</form>
}
Action:
[HttpPost]
[ValidateAntiForgeryToken]
public IActionResult AddToCart(int gameId,int amount)
{
//do your stuff...
}
Result:

ASP.NET Core 2.2 id passed to controller is always 0

I'm creating an auction website and when submitting a bid, I'm trying to pass the id of the auction to the bid form so that I can associate the bid with an auction.
However, no matter what I do, the auction id being passed to the EnterBid controller is always 0. specifically the auctionItemId and auctionStartingBid in the EnterBid controller are always 0.
Here's my code:
EnterBid controller:
[HttpPost]
[ValidateAntiForgeryToken]
public async Task<IActionResult> EnterBid(int auctionItemId, int auctionStartingBidAmount, [Bind("BidId,BidderName,BidderPhone,BidderEmail,BidderAddress,BidAmount,AuctionItemModel")] AuctionBidModel auctionBidModel)
{
var auctionItemModel = await _context.AuctionItems.FindAsync(auctionItemId);
auctionBidModel.AuctionItemModel = auctionItemModel;
float currentHighestBidAmount = auctionStartingBidAmount;
if (auctionBidModel.AuctionItemModel.Bids != null)
{
foreach (AuctionBidModel bid in auctionBidModel.AuctionItemModel.Bids)
{
if (bid.BidAmount > currentHighestBidAmount)
{
auctionBidModel.AuctionItemModel.CurrentHighestBid = bid;
currentHighestBidAmount = bid.BidAmount;
}
}
}
if (ModelState.IsValid)
{
_context.Add(auctionBidModel);
await _context.SaveChangesAsync();
return RedirectToAction(nameof(Index));
}
return View("EnterBid", auctionBidModel);
}
Details controller (for viewing details on an auction, contains the link to enter the bid):
public async Task<IActionResult> Details(int? id)
{
if (id == null)
{
return NotFound();
}
var auctionItemModel = await _context.AuctionItems.FirstOrDefaultAsync(m => m.ListingId == id);
if (auctionItemModel == null)
{
return NotFound();
}
return View(auctionItemModel);
}
// GET: Search/Create
public IActionResult Create()
{
return View();
}
Details view:
#model Showcase.Models.AuctionItemModel
#{
ViewData["Title"] = "Details";
}
<h1>Details</h1>
<div>
<h4>AuctionItemModel</h4>
<hr />
<dl class="row">
<dt class = "col-sm-2">
#Html.DisplayNameFor(model => model.Name)
</dt>
<dd class = "col-sm-10">
#Html.DisplayFor(model => model.Name)
</dd>
<dt class = "col-sm-2">
#Html.DisplayNameFor(model => model.StartingBidAmount)
</dt>
<dd class = "col-sm-10">
#Html.DisplayFor(model => model.StartingBidAmount)
</dd>
<dt class = "col-sm-2">
#Html.DisplayNameFor(model => model.AuctionStartTime)
</dt>
<dd class = "col-sm-10">
#Html.DisplayFor(model => model.AuctionStartTime)
</dd>
<dt class = "col-sm-2">
#Html.DisplayNameFor(model => model.AuctionEndTime)
</dt>
<dd class = "col-sm-10">
#Html.DisplayFor(model => model.AuctionEndTime)
</dd>
<dt class = "col-sm-2">
#Html.DisplayNameFor(model => model.Description)
</dt>
<dd class = "col-sm-10">
#Html.DisplayFor(model => model.Description)
</dd>
<dt class = "col-sm-2">
#Html.DisplayNameFor(model => model.ListingImage)
</dt>
<dd class = "col-sm-10">
#Html.DisplayFor(model => model.ListingImage)
</dd>
</dl>
</div>
<div>
<a asp-action="Edit" asp-route-id="#Model.ListingId">Edit</a> |
<a asp-action="Index">Back to List</a>
</div>
<div><a asp-action="EnterBid" asp-route-auctionItemId="#Model.ListingId" asp-route-auctionStartingBidAmount="#Model.StartingBidAmount">Submit a Bid</a></div>
EnterBid view:
#model Showcase.Models.AuctionBidModel
#{
ViewData["Title"] = "EnterBid";
}
<h1>EnterBid</h1>
<h4>AuctionBidModel</h4>
<hr />
<div class="row">
<div class="col-md-4">
<form asp-action="EnterBid">
<div asp-validation-summary="ModelOnly" class="text-danger"></div>
<div class="form-group">
<label asp-for="BidderName" class="control-label"></label>
<input asp-for="BidderName" class="form-control" />
<span asp-validation-for="BidderName" class="text-danger"></span>
</div>
<div class="form-group">
<label asp-for="BidderPhone" class="control-label"></label>
<input asp-for="BidderPhone" class="form-control" />
<span asp-validation-for="BidderPhone" class="text-danger"></span>
</div>
<div class="form-group">
<label asp-for="BidderEmail" class="control-label"></label>
<input asp-for="BidderEmail" class="form-control" />
<span asp-validation-for="BidderEmail" class="text-danger"></span>
</div>
<div class="form-group">
<label asp-for="BidderAddress" class="control-label"></label>
<input asp-for="BidderAddress" class="form-control" />
<span asp-validation-for="BidderAddress" class="text-danger"></span>
</div>
<div class="form-group">
<label asp-for="BidAmount" class="control-label"></label>
<input asp-for="BidAmount" class="form-control" />
<span asp-validation-for="BidAmount" 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-action="Index">Back to List</a>
</div>
#section Scripts {
#{await Html.RenderPartialAsync("_ValidationScriptsPartial");}
}
So I was able to figure it out, I needed to add a route attribute tag before the EnterBid controller, so it now looks like this:
[HttpPost]
[ValidateAntiForgeryToken]
[Route("Search/EnterBid/{auctionItemId}")]
public async Task<IActionResult> EnterBid(int auctionItemId, [Bind("BidId,BidderName,BidderPhone,BidderEmail,BidderAddress,BidAmount,AuctionItemModel")] AuctionBidModel auctionBidModel)
I still have some strange issues if I try to set it up for both parameters (the id and the starting price) but otherwise it works, and I have a workaround for that in the meantime.

In ASP Core, where do the parameters of the POST controller method come from when the form doesn't match the prototype?

In the ms docs .NET core tutorial the Edit View posts all data for the department but the Post controller method only accepts id and row version. In the delete method only the DepartmentID and RowVersion are posted but the Controller Delete post method accepts a Full Department instance. Where does this instance come from because it determines how concurrency error will be handled. Is the model for the page secretly passed instead?
Edit View
#model ContosoUniversity.Models.Department
#{
ViewData["Title"] = "Edit";
}
<h2>Edit</h2>
<h4>Department</h4>
<hr />
<div class="row">
<div class="col-md-4">
<form asp-action="Edit">
<div asp-validation-summary="ModelOnly" class="text-danger">
</div>
<input type="hidden" asp-for="DepartmentID" />
<input type="hidden" asp-for="RowVersion" />
<div class="form-group">
<label asp-for="Name" class="control-label"></label>
<input asp-for="Name" class="form-control" />
<span asp-validation-for="Name" class="text-danger"></span>
</div>
<div class="form-group">
<label asp-for="Budget" class="control-label"></label>
<input asp-for="Budget" class="form-control" />
<span asp-validation-for="Budget" class="text-danger">
</span>
</div>
<div class="form-group">
<label asp-for="StartDate" class="control-label"></label>
<input asp-for="StartDate" class="form-control" />
<span asp-validation-for="StartDate" class="text-danger">
</span>
</div>
<div class="form-group">
<label asp-for="InstructorID" class="control-label"></label>
<select asp-for="InstructorID" class="form-control" asp-
items="ViewBag.InstructorID">
<option value="">-- Select Administrator --</option>
</select>
<span asp-validation-for="InstructorID" class="text-danger">
</span>
</div>
<div class="form-group">
<input type="submit" value="Save" class="btn btn-default" />
</div>
</form>
</div>
</div>
<div>
<a asp-action="Index">Back to List</a>
</div>
#section Scripts {
#{await Html.RenderPartialAsync("_ValidationScriptsPartial");}
}
Edit Post in Controller
[HttpPost]
[ValidateAntiForgeryToken]
public async Task<IActionResult> Edit(int? id, byte[] rowVersion)
{
if (id == null)
{
return NotFound();
}
var departmentToUpdate = await _context.Departments.Include(i =>
i.Administrator).SingleOrDefaultAsync(m => m.DepartmentID == id);
/*Lots of other stuff unimportant to the question...*/
Delete View
#model ContosoUniversity.Models.Department
#{
ViewData["Title"] = "Delete";
}
<h2>Delete</h2>
<p class="text-danger">#ViewData["ConcurrencyErrorMessage"]</p>
<h3>Are you sure you want to delete this?</h3>
<div>
<h4>Department</h4>
<hr />
<dl class="dl-horizontal">
<dt>
#Html.DisplayNameFor(model => model.Name)
</dt>
<dd>
#Html.DisplayFor(model => model.Name)
</dd>
<dt>
#Html.DisplayNameFor(model => model.Budget)
</dt>
<dd>
#Html.DisplayFor(model => model.Budget)
</dd>
<dt>
#Html.DisplayNameFor(model => model.StartDate)
</dt>
<dd>
#Html.DisplayFor(model => model.StartDate)
</dd>
<dt>
#Html.DisplayNameFor(model => model.Administrator)
</dt>
<dd>
#Html.DisplayFor(model => model.Administrator.FullName)
</dd>
</dl>
<form asp-action="Delete">
<input type="hidden" asp-for="DepartmentID" />
<input type="hidden" asp-for="RowVersion" />
<div class="form-actions no-color">
<input type="submit" value="Delete" class="btn btn-default" /> |
<a asp-action="Index">Back to List</a>
</div>
</form>
</div>
Delete Post
[HttpPost]
[ValidateAntiForgeryToken]
public async Task<IActionResult> Delete(Department department)
{
try
{
if (await _context.Departments.AnyAsync(m => m.DepartmentID == department.DepartmentID))
{
_context.Departments.Remove(department);
await _context.SaveChangesAsync();
}
return RedirectToAction(nameof(Index));
}
catch (DbUpdateConcurrencyException /* ex */)
{
//Log the error (uncomment ex variable name and write a log.)
return RedirectToAction(nameof(Delete), new { concurrencyError =
true, id = department.DepartmentID });
}
}

When model is not valid, return to partial view inside a view, with error message using asp.net core

I´ve got a modal boostrap. I want to show the error of validation on boostrap modal. But when I leave the model empty and click on submit button Its just viewed as a standalone page.
Partial view:
#model WebApplication1.Models.Book
<form asp-controller="Home" asp-action="AddBook"
data-ajax="true" data-ajax-method="POST" data-ajax-mode="replace" data-ajax-update="#frmaddbook">
<div class="modal-header">
<button type="button" class="close" data-dismiss="modal" aria-label="Close">
<span aria-hidden="true">×</span>
</button>
<h4 class="modal-title" id="myModalLabel">Header of Modal</h4>
</div>
<div class="modal-body form-horizontal" id="frmaddbook ">
<span class="alert-danger">
#Html.ValidationSummary()
</span>
<div class="row">
<div class="form-group">
<label asp-for="BookName" class="col-lg-3 col-sm-3 control-label"></label>
<div class="col-lg-6">
<input asp-for="BookName" class="form-control" />
<span asp-validation-for="BookName" class="text-danger"></span>
</div>
</div>
<div class="form-group">
<label asp-for="BookDescription" class="col-lg-3 col-sm-3 control-label"></label>
<div class="col-lg-6">
<input asp-for="BookDescription" class="form-control" />
<span asp-validation-for="BookDescription" class="text-danger"></span>
</div>
</div>
</div>
</div>
<div class="modal-footer">
<input type="submit" class="btn btn-primary" value="Submit" />
</div>
Index View :
<div class="panel panel-primary">
<div class="panel-body">
<div class="btn-group">
<a class="btn btn-primary marginbutoon" id="showBookgroup" data-toggle="modal" asp-action="AddBook"
data-target="#modal-book">
<i class="glyphicon glyphicon-plus"></i>
Add Book
</a>
</div>
</div>
i use this libraries at top of index view:
jquery.unobtrusive-ajax.min.js
jquery.validate.unobtrusive.min.js
and use at the bottom of index view:
<script src="~/js/book-index.js"></script>
book-index.js:
(function ($) {
function Home() {
var $this = this;
function initilizeModel() {
$("#modal-book").on('loaded.bs.modal', function (e) {
}).on('hidden.bs.modal', function (e) {
$(this).removeData('bs.modal');
});
}
$this.init = function () {
initilizeModel();
}
}
$(function () {
var self = new Home();
self.init();
})
}(jQuery))
Controller:
[HttpGet]
public IActionResult AddBook()
{
var b = new Book();
return PartialView("_AddBook", b);
}
[HttpPost]
[ValidateAntiForgeryToken]
//[HandleError]//not in core
public IActionResult AddBook(Book model)
{
if (ModelState.IsValid)
{
return RedirectToAction("Index");
}
return PartialView("_AddBook", model);
}
Model :
public class Book
{
[Key]
public int BookId { get; set; }
[Display(Name = "Book Name :")]
[Required(ErrorMessage = "Enter Book Name Please ")]
public string BookName { get; set; }
[Display(Name = "Book Description")]
[Required(ErrorMessage = "Enter Book Description Please ")]
public string BookDescription { get; set; }
}
My code is shown above. How can i show validation error in modal partial view ?
You can set the Id of form as the data-ajax-update property value of the form , which is ajaxified. This value will be used as the jQuery selector when the result is received from the ajax call.
#model Book
<form asp-controller="Home" asp-action="AddBook" id="myform"
data-ajax="true" data-ajax-method="POST"
data-ajax-mode="replace" data-ajax-update="#myform">
<div class="modal-header">
<button type="button" class="close" data-dismiss="modal" aria-label="Close">
<span aria-hidden="true">×</span>
</button>
<h4 class="modal-title" id="myModalLabel">Add Book</h4>
</div>
<div class="modal-body form-horizontal" id="frmaddbook ">
<span class="alert-danger">
#Html.ValidationSummary()
</span>
<div class="row">
<div class="form-group">
<label asp-for="BookName" class="col-sm-3 control-label"></label>
<div class="col-lg-6">
<input asp-for="BookName" class="form-control" />
<span asp-validation-for="BookName" class="text-danger"></span>
</div>
</div>
</div>
</div>
<div class="modal-footer">
<input type="submit" class="btn btn-primary" value="Submit" />
</div>
</form>
Now when you submit the form and model state validation fails, the action method code will return the partial view result with the validation error messages (generated by the validation helpers) and the jquery.unobtrusive-ajax.js library code will replace (because we specified that with data-ajax-mode="replace") the content of the result of the jquery selector #data-ajax-update (the form tag and it's inner contents) with the response coming back from the server.

Resources