I'm trying to add a "Create" to one of my Controllers (LeagueController), so I created a Create View, which uses my League object.
However, when I go to submit the form, it does not redirect back to the Index view, as I want it to, nor does it enter the log entry to say that I created a league.
League Class
public class League : BaseEntity
{
[Required]
[DataType(DataType.Text)]
public string LeagueName { get; set; }
[Required]
[DataType(DataType.Text)]
public string LeagueInitials { get; set; }
[DataType(DataType.Text)]
public string LeagueURL { get; set; }
[DataType(DataType.DateTime)]
public DateTime Founded { get; set; }
[InverseProperty("League")]
public ICollection<Team> Teams { get; set; }
[ForeignKey("LeagueID")]
public ICollection<LeagueOwners> LeagueOwners { get; set; }
}
LeaguesController Class
public class LeaguesController : Controller
{
private MyDBContext context;
private ILogger logger;
public LeaguesController(MyDBContext context, ILogger logger)
{
this.context = context;
this.logger = logger;
}
public IActionResult Index()
{
this.logger.LogInformation("Reached League Index");
return View();
}
[Route("Create")]
public IActionResult Create()
{
this.logger.LogInformation("Creating a league");
return View();
}
[HttpPost]
public IActionResult Create(League league)
{
this.logger.LogInformation("Create button clicked!");
return this.RedirectToAction("Index");
}
}
Create.cshtml
#model MySite.Core.Entities.League
#{
ViewData["Title"] = "Create";
Layout = "~/Views/Shared/_Layout.cshtml";
}
<h2>Create</h2>
<h4>League</h4>
<hr />
<div class="row">
<div class="col-md-4">
<form asp-action="Create" method="post">
<div asp-validation-summary="ModelOnly" class="text-danger"></div>
<div class="form-group">
<label asp-for="LeagueName" class="control-label"></label>
<input asp-for="LeagueName" class="form-control" />
<span asp-validation-for="LeagueName" class="text-danger"></span>
</div>
<div class="form-group">
<label asp-for="LeagueInitials" class="control-label"></label>
<input asp-for="LeagueInitials" class="form-control" />
<span asp-validation-for="LeagueInitials" class="text-danger"></span>
</div>
<div class="form-group">
<label asp-for="LeagueURL" class="control-label"></label>
<input asp-for="LeagueURL" class="form-control" />
<span asp-validation-for="LeagueURL" class="text-danger"></span>
</div>
<div class="form-group">
<label asp-for="Founded" class="control-label"></label>
<input asp-for="Founded" class="form-control" />
<span asp-validation-for="Founded" class="text-danger"></span>
</div>
<div class="form-group" hidden="hidden">
<label asp-for="Created" class="control-label"></label>
<input asp-for="Created" class="form-control" value="#DateTime.Now" />
<span asp-validation-for="Created" class="text-danger"></span>
</div>
<div class="form-group" hidden="hidden">
<label asp-for="Modified" class="control-label"></label>
<input asp-for="Modified" class="form-control" value="#DateTime.Now" />
<span asp-validation-for="Modified" class="text-danger"></span>
</div>
<div class="form-group">
<input type="submit" value="Create" class="btn btn-default" />
</div>
</form>
</div>
</div>
<div>
<a asp-action="Index">Back to List</a>
</div>
The first way is that you could delete [Route("Create")]which is on your get method.
The second way is that you could add [Route] attribute to your post method like below:
[Route("Create")]
public IActionResult Create()
{
this.logger.LogInformation("Creating a league");
return View();
}
[Route("Create")]
[HttpPost]
public IActionResult Create(League league)
{
this.logger.LogInformation("Create button clicked!");
return this.RedirectToAction("Index");
}
In your form <form asp-action="Create" method="post"> add a tag to point to the correct controller asp-controller="Leagues"
Do not enforce the route, that's just anti-pattern.
Related
I have a problem, where I have a form, and some of the data is not being set in the model and I don't know why or where to look.
My Model:
using System;
using System.Collections.Generic;
using System.ComponentModel.DataAnnotations;
using System.Linq;
using System.Threading.Tasks;
namespace VolunteerMngSystm.Models
{
public class Organisations
{
public int ID { get; set; }
[Required]
public string Organisation_name { get; set; }
[Required]
public string Industry { get; set; }
[Required]
public string Email { get; set; }
[Required]
public string OrganisationsID { get; set; }
}
}
The Email and OrganisationID are not being set.
My Controller Action method:
[HttpPost]
[ValidateAntiForgeryToken]
public async Task<IActionResult> OrgReg([Bind("Organisation_name,Industry,Email,OrganisationID")] Organisations organisations)
{
try
{
if (ModelState.IsValid)
{
_context.Add(organisations);
await _context.SaveChangesAsync();
return RedirectToAction(nameof(OrgHome));
}
}
catch (DbUpdateException e)
{
//Log the error (uncomment ex variable name and write a log.
ModelState.AddModelError("" + e, "Unable to save changes. " +
"Try again, and if the problem persists " +
"see your system administrator.");
}
return View(organisations);
}
My View:
#model VolunteerMngSystm.Models.Organisations;
#{
ViewData["Title"] = "Register";
}
<h1>Register</h1>
<h5>As Organisation</h5>
<hr />
<div class="row">
<div class="col-md-4">
<form asp-action="OrgReg">
<div asp-validation-summary="ModelOnly" class="text-danger"></div>
<div class="form-group">
<label asp-for="Organisation_name" class="control-label">Organisation Name</label>
<input asp-for="Organisation_name" class="form-control" />
<span asp-validation-for="Organisation_name" class="text-danger"></span>
</div>
<div class="form-group">
<label asp-for="Industry" class="control-label"></label>
<input asp-for="Industry" class="form-control" />
<span asp-validation-for="Industry" class="text-danger"></span>
</div>
<div class="form-group">
<label asp-for="Email" class="control-label"></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="OrganisationsID" class="control-label">Verification ID</label>
<input asp-for="OrganisationsID" type="file" accept="image/* " />
<span asp-validation-for="OrganisationsID" class="text-danger"></span>
</div>
<div class="form-group">
<input type="submit" value="Register" class="btn btn-primary" />
</div>
</form>
</div>
</div>
<div>
<a asp-action="Index">Back to List</a>
</div>
#section Scripts {
#{await Html.RenderPartialAsync("_ValidationScriptsPartial");}
}
Can anyone please advise me on where to look or how to fix this problem, please?
Since your action need AntiForgeryToken, add it to your form
<form asp-action="OrgReg">
<div asp-validation-summary="ModelOnly" class="text-danger"></div>
#Html.AntiForgeryToken()
or remove it from the action
also try to remove [Bind] from the action. You have a typo there and you don't need it since you are binding all properties any way.
[HttpPost]
[ValidateAntiForgeryToken]
public async Task<IActionResult> OrgReg( Organisations organisations)
This is my Index Action,
I give all products to my view
public async Task<IActionResult> Index()
{
return View(await _productRepo.GetAllAsync());
}
This is my Create Action,
I selected all categories Id and Name to View.Categories
[HttpPost]
[ValidateAntiForgeryToken]
public async Task<IActionResult> Create([Bind("Id,Name,SKU,Description,Price,OldPrice,Status,IsMenuItem,Count,CategoryId")] Product productModel)
{
ViewBag.Categories = new SelectList(await _categoryrepo.GetAllAsync() , "Id" , "Name");
if (ModelState.IsValid)
{
await _productRepo.CreateAsync(productModel);
return RedirectToAction(nameof(Index));
}
return View(productModel);
}
This is my view
#model OnlineShopArmenia.Models.Product
#{
ViewData["Title"] = "Create";
}
<h1>Create</h1>
<h4>Product</h4>
<hr />
<div class="row">
<div class="col-md-4">
<form asp-action="Create">
<div asp-validation-summary="ModelOnly" class="text-danger"></div>
<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="SKU" class="control-label"></label>
<input asp-for="SKU" class="form-control" />
<span asp-validation-for="SKU" class="text-danger"></span>
</div>
<div class="form-group">
<label asp-for="Description" class="control-label"></label>
<input asp-for="Description" class="form-control" />
<span asp-validation-for="Description" class="text-danger"></span>
</div>
<div class="form-group">
<label asp-for="Price" class="control-label"></label>
<input asp-for="Price" class="form-control" />
<span asp-validation-for="Price" class="text-danger"></span>
</div>
<div class="form-group form-check">
<label class="form-check-label">
<input class="form-check-input" asp-for="Status" /> #Html.DisplayNameFor(model => model.Status)
</label>
</div>
<div class="form-group form-check">
<label class="form-check-label">
<input class="form-check-input" asp-for="IsMenuItem" /> #Html.DisplayNameFor(model => model.IsMenuItem)
</label>
</div>
<div class="form-group">
<label asp-for="Count" class="control-label"></label>
<input asp-for="Count" class="form-control" />
<span asp-validation-for="Count" class="text-danger"></span>
</div>
<div class="form-group">
<label>Categories :</label>
<select name="Id" asp-for="Id" class="formcontrol" asp-items="ViewBag.Categories">
<option value="#ViewBag.Categories"></option>
</select>
<span asp-validation-for="Id" 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");}
}
This is Product Model
public class Product
{
[Key]
public int Id { get; set; }
[Required]
public string Name { get; set; }
public string SKU { get; set; }
public string Description { get; set; }
public decimal Price { get; set; }
public bool Status { get; set; }
public bool IsMenuItem { get; set; }
public int Count { get; set; }
public int? CategoryId { get; set; }
public Category Category { get; set; }
}
This is Category Model
public class Category
{
[Key]
public int Id { get; set; }
public string Name { get; set; }
}
This is the result
I want to see Categories in dropdown list, how can I do it ?
I think that we must change attributes in <select> and <option> tags,
Please, help me to fix it
You are using the wrong action method. For create operation your controller should have two action methods - a GET method and a POST method. The one you are using now (marked with [HttpPost]) is for receiving data from your view, once you try to save them. To pass data to the view (while you are creating it), use an action method marked with [HttpGet] attribute (or, not marked with any attribute at all). Following GET method should be sufficient to create your view -
[HttpGet] // this attribute is optional
public IActionResult Create()
{
ViewBag.Categories = new SelectList(await _categoryrepo.GetAllAsync() , "Id" , "Name");
return View();
}
You are marking the select tag wrong, it should represent the foreign key property CategoryId, not the Id of the product -
<select asp-for="CategoryId" class ="form-control" asp-items="ViewBag.Categories"></select>
You don't need the option tag unless you want a display-value like Please select a Category or something -
<select asp-for="CategoryId" class ="form-control" asp-items="ViewBag.Categories">
<option value="">Please choose user category:</option>
</select>
EDIT :
I'm not sure what version of ASP.NET MVC or, ASP.NET Core MVC you are using, but the razor syntax above works in .NET 5.
you should have 2 actions -to create or edit view and save data.
Your action to create view should be looking like this:
[HttpGet] // this attribute is optional
public async Task<IActionResult> Create()
{
return await Edit(0);
}
[HttpGet("{id?}")]
public async Task<IActionResult> Edit(int id)
{
ProductModel model=null;
if id=0 model=new Product();
else model= await _productRepo.GetAsync(id);
ViewBag.Categories = new SelectList(await _categoryrepo.GetAllAsync()
, "Id" , "Name");
return View(model);
}
and fix your select:
<select name="categoryId" asp-for="CategoryId" class="formcontrol" asp-items="#ViewBag.Categories">
</select>
My HttpPost Edit task is not giving me my list of EventMembers. I put a watch on the GET for my Edit task and it reads my EventMembers just fine. but when i get my POST Edit my EventMembers only shows System.Collections.Generic.List`1[System.String] in my watch window, as well as my input box in my view. Whats happening?
Model:
public class Event
{
[Required]
public int EventId { get; set; }
[ForeignKey("UserId")]
public virtual SchedulerUser SchedulerUser { get; set; }
[MaxLength(50)]
public string EventCreator { get; set; }
public List<string> EventMembers { get; set; }
[Required]
[MaxLength(100)]
public string Subject { get; set; }
[MaxLength(400)]
public string Description { get; set; }
[Required]
public DateTime StartTime { get; set; }
public DateTime? EndTime { get; set; }
[Required]
public bool IsFullDay { get; set; }
[Required]
public bool AcceptOrDecline { get; set; }
}
Controller:
// GET: Events/Edit/5
public async Task<IActionResult> Edit(int? id)
{
if (id == null)
{
return NotFound();
}
var #event = await _context.Events.FindAsync(id);
if (#event == null)
{
return NotFound();
}
return View(#event);
}
// POST: Events/Edit/5
[HttpPost]
[ValidateAntiForgeryToken]
public async Task<IActionResult> Edit(int id, [Bind("EventId,UserId,EventCreator,EventMembers,Subject,Description,StartTime,EndTime,IsFullDay,AcceptOrDecline")] Event #event)
{
if (id != #event.EventId)
{
return NotFound();
}
if (ModelState.IsValid)
{
try
{
#event.SchedulerUser = await _userManager.GetUserAsync(HttpContext.User);
_context.Update(#event);
if (#event.AcceptOrDecline == false)
{
_context.Remove(#event);
}
await _context.SaveChangesAsync();
}
catch (DbUpdateConcurrencyException)
{
if (!EventExists(#event.EventId))
{
return NotFound();
}
else
{
throw;
}
}
return RedirectToAction(nameof(Index));
}
return View(#event);
}
View:
#model Scheduler.Models.Event
#{
ViewData["Title"] = "Edit";
Layout = "~/Views/Shared/_Layout.cshtml";
}
<h1>Edit</h1>
<h4>Event</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="EventId" />
<div class="form-group">
<label asp-for="Subject" class="control-label"></label>
<input asp-for="Subject" class="form-control" />
<span asp-validation-for="Subject" class="text-danger"></span>
</div>
<div class="form-group">
<label asp-for="Description" class="control-label"></label>
<input asp-for="Description" class="form-control" />
<span asp-validation-for="Description" class="text-danger"></span>
</div>
<div class="form-group">
<label asp-for="EventMembers" class="control-label"></label>
<input asp-for="EventMembers" class="form-control" />
<span asp-validation-for="EventMembers" class="text-danger"></span>
</div>
<div class="form-group">
<label asp-for="StartTime" class="control-label">Start Time</label>
<input asp-for="StartTime" class="form-control" />
<span asp-validation-for="StartTime" class="text-danger"></span>
</div>
<div class="form-group">
<label asp-for="EndTime" class="control-label">End Time</label>
<input asp-for="EndTime" class="form-control" />
<span asp-validation-for="EndTime" class="text-danger"></span>
</div>
<div class="form-group form-check">
<label class="form-check-label">
<input class="form-check-input" asp-for="IsFullDay" /> All Day
</label>
</div>
<div class="form-group form-check">
<label class="form-check-label">
<input class="form-check-input" asp-for="AcceptOrDecline" /> Accepted
</label>
<p style="color:red; font-weight:bold;">Uncheck this to decline invitation. Event will be removed from your schedule.</p>
</div>
<div class="form-group">
<input type="submit" value="Save" class="btn btn-primary" />
</div>
</form>
</div>
</div>
<div>
<a asp-action="Index">Back to List</a>
</div>
#section Scripts {
#{await Html.RenderPartialAsync("_ValidationScriptsPartial");}
}
Since your EventMembers model property is an Enumerable list, the Html control which represents the property should be indexed.
<div class="form-group">
<label asp-for="EventMembers[0]" class="control-label"></label>
<input asp-for="EventMembers[0]" class="form-control" />
<span asp-validation-for="EventMembers[0]" class="text-danger"></span>
</div>
<div class="form-group">
...
<input asp-for="EventMembers[1]" class="form-control" />
...
</div>
The best practice is to generate the control inside a loop.
#for (int i = 0; i < Model.EventMembers.Count; i++)
{
<div class="form-group">
...
<input asp-for="EventMembers[i]" class="form-control" />
...
</div>
}
I have a Register form which uses the Compare Attribute to compare the password and confirm password. When I enter in different passwords it does what it is supposed to and says "Passwords do not match". The issue comes when I hit the submit button and "Post" it. I hit a breakpoint at "if (!ModelState.IsValid)" where ModelState is not valid. When it reloads the page where it used to say "Passwords do not match" it now says "Could not find a property named Password." I tried doing what this post said to try and put in the answer's code. All it returns is that the error is "null".
Razor Page:
#page
#model ThinBlueLie.Pages.RegisterModel
#{
ViewBag.Title = "Register";
}
<div class="container-fluid h-100 row nogap">
<div class="card border-secondary mx-auto center col-lg-3 col-md-4 p-0" style="margin-top:100px;">
<div class="card-header">
Register
<a class="float-right" asp-page="/Login">Login</a>
</div>
<form method="post">
<div class="card-body text-secondary">
<div class="form-group">
<label asp-for="Users.Email" class="control-label">Email</label>
<input type="email" asp-for="Users.Email" class="form-control">
<span asp-validation-for="Users.Email" class="text-danger"></span>
</div>
<div class="form-group">
<label asp-for="Password"class="control-label"></label>
<input asp-for="Password" type="password" class="form-control" >
<span asp-validation-for="Password" class="text-danger"></span>
</div>
<div class="form-group">
<label asp-for="ConfirmPassword" class="control-label"></label>
<input type="password" asp-for="ConfirmPassword" class="form-control">
<span asp-validation-for="ConfirmPassword" class="text-danger"></span>
</div>
<div class="form-group">
<label asp-for="Users.Username" class="control-label"></label>
<input type="text" asp-for="Users.Username" class="form-control">
<span asp-validation-for="Users.Username" class="text-danger"></span>
</div>
<div class="form-group">
<input type="submit" value="Register" class="btn btn-primary mb-1" style="float:right" />
</div>
</div>
</form>
<div class="card-footer">
<a>Log in with Google</a>
</div>
</div>
</div>
#section Scripts {
#{await Html.RenderPartialAsync("_ValidationScriptsPartial");}
}
PageModel:
namespace ThinBlueLie.Pages
{
public class RegisterModel : PageModel
{
private readonly DataAccessLibrary.thinblue.ThinbluelieContext _context;
public RegisterModel(DataAccessLibrary.thinblue.ThinbluelieContext context)
{
_context = context;
}
public IActionResult OnGet()
{
return Page();
}
public Users Users { get; set; }
[BindProperty]
[Required]
[DataType(DataType.Password)]
public string Password { get; set; }
[Required]
[BindProperty]
[DataType(DataType.Password)]
[Display(Name = "Confirm Password")]
[Compare("Password", ErrorMessage = "Passwords do not match")]
public string ConfirmPassword { get; set; }
// To protect from overposting attacks, enable the specific properties you want to bind to, for
// more details, see https://aka.ms/RazorPagesCRUD.
public async Task<IActionResult> OnPostAsync()
{
var errors = ModelState.Values.SelectMany(v => v.Errors);
if (!ModelState.IsValid)
{
return Page();
}
_context.Users.Add(Users);
await _context.SaveChangesAsync();
return RedirectToPage("./Index");
}
}
}
Model:
namespace DataAccessLibrary.thinblue
{
public partial class Users
{
public int IdUsers { get; set; }
[BindProperty]
public string Username { get; set; }
[BindProperty]
[Required]
[EmailAddress]
public string Email { get; set; }
public string Password { get; set; }
}
}
I reproduce your error,and I put Password and ConfirmPassword in the same model,and it works.Here is a demo:
PassWordModel:
public class PassWordModel
{
[BindProperty]
[Required]
[DataType(DataType.Password)]
public string Password { get; set; }
[Required]
[BindProperty]
[DataType(DataType.Password)]
[Display(Name = "Confirm Password")]
[Compare("Password", ErrorMessage = "Passwords do not match")]
public string ConfirmPassword { get; set; }
}
cshtml.cs:
public class RegisterModel : PageModel
{
public IActionResult OnGet()
{
return Page();
}
public Users Users { get; set; }
[BindProperty]
public PassWordModel passWordModel { get; set; }
public async Task<IActionResult> OnPostAsync()
{
if (!ModelState.IsValid)
{
return Page();
}
return RedirectToPage("./Index");
}
}
cshtml:
<div class="container-fluid h-100 row nogap">
<div class="card border-secondary mx-auto center col-lg-3 col-md-4 p-0" style="margin-top:100px;">
<div class="card-header">
Register
<a class="float-right" asp-page="/Login">Login</a>
</div>
<form method="post">
<div class="card-body text-secondary">
<div class="form-group">
<label asp-for="Users.Email" class="control-label">Email</label>
<input type="email" asp-for="Users.Email" class="form-control">
<span asp-validation-for="Users.Email" class="text-danger"></span>
</div>
<div class="form-group">
<label asp-for="passWordModel.Password" class="control-label"></label>
<input asp-for="passWordModel.Password" type="password" class="form-control">
<span asp-validation-for="passWordModel.Password" class="text-danger"></span>
</div>
<div class="form-group">
<label asp-for="passWordModel.ConfirmPassword" class="control-label"></label>
<input type="password" asp-for="passWordModel.ConfirmPassword" class="form-control">
<span asp-validation-for="passWordModel.ConfirmPassword" class="text-danger"></span>
</div>
<div class="form-group">
<label asp-for="Users.Username" class="control-label"></label>
<input type="text" asp-for="Users.Username" class="form-control">
<span asp-validation-for="Users.Username" class="text-danger"></span>
</div>
<div class="form-group">
<input type="submit" value="Register" class="btn btn-primary mb-1" style="float:right" />
</div>
</div>
</form>
<div class="card-footer">
<a>Log in with Google</a>
</div>
</div>
</div>
#section Scripts {
#{await Html.RenderPartialAsync("_ValidationScriptsPartial");}
}
result:
I have a ViewModel named CreateRoleViewModel which contains the items shown below. On the view, I'm iterating through a list of permissions and displaying them. What I'm trying to accomplish is to allow a user to create a new role and add permissions to that role. I've been able to successfully pass all data to the controller except the permissions. Hopefully I'm not confusing anyone. I've tried to use a for loop (which did't produce correct results) and a foreach loop, which did produce the correct results (meaning displayed all permissions currently available). I realize I'm going to also, most likely need to update my domain model for Permissions to include columns for View, Modify etc.
CreateViewModel
public class CreateRoleViewModel
{
[Required]
public string RoleName { get; set; }
public string RoleDescription { get; set; }
public List<Permissions> Permissions { get; set; }
public bool AllowViewAccess { get; set; }
public bool AllowModifyAccess { get; set; }
public CreateRoleViewModel()
{
Permissions = new List<Permissions>();
}
}
PermissionsController
[Route("Administration/Permissions/CreateRole")]
[HttpPost]
[ValidateAntiForgeryToken]
public ActionResult CreateRole(CreateRoleViewModel newRole)
{
try
{
var test = newRole;
return RedirectToAction(nameof(Index));
}
catch
{
return View();
}
}
View
<form method="post" asp-action="CreateRole">
<div class="form-group col-6" style="padding-left:0">
<label asp-for="RoleName"></label>
<input asp-for="RoleName" class="form-control" />
<span asp-validation-for="RoleName" class="text-danger"></span>
</div>
<div class="form-group col-6" style="padding-left:0">
<label asp-for="RoleDescription"></label>
<input asp-for="RoleDescription" class="form-control" />
</div>
<div class="form-group ">
<h4>Permissions</h4>
<div class="card">
<div class="card-header">
<input type="checkbox" class="form-check-input p-2" id="selectAll">
<label class="form-check-label" for="selectAll">Select All<span style="font-weight:bold;font-style:italic;"> (This will allow read/write access to ALL selected items.)</span></label>
</div>
</div>
<!--Permissions should go here-->
<div class="card-body border">
#foreach (var item in Model.Permissions)
{
<div class="row" style="border-radius:3px;border-top:2px solid gray;border-bottom:2px solid gray;padding:15px;">
<div class="col-8">
<input type="checkbox" class="form-check-input p-2" id="select">
<label class="form-check-label" for="select" style="font-weight:bold;">#item.PermissionName</label>
<p style="color:gray;">#item.PermissionDescription</p>
</div>
<div class="col-2">
<input type="checkbox" class="form-check-input p-2" id="readOnly" asp-for="AllowViewAccess">
<label class="form-check-label" for="readOnly">View</label>
</div>
<div class="col-2">
<input type="checkbox" class="form-check-input p-2" id="readWrite" asp-for="AllowModifyAccess">
<label class="form-check-label" for="readWrite">Modify</label>
</div>
</div>
}
</div>
<div asp-validation-summary="All" class="text-info"></div>
<button style="background-color: #6987D5;color:white;" class="btn">Save</button>
<button class="btn" style="background-color:lightgray;border:1px solid darkgray">Cancel</button>
</div>
</form>
From your description and the view code, I think you should put the "AllowViewAccess " and "AllowModifyAccess " in the Permissions class, because the role have separate "View" or "Modify" access to different permissions. Based on your codes, I made an example:
Model:
public class CreateRoleViewModel
{
[Required]
public string RoleName { get; set; }
public string RoleDescription { get; set; }
public List<Permissions> Permissions { get; set; }
public CreateRoleViewModel()
{
Permissions = new List<Permissions>();
}
}
public class Permissions
{
public string PermissionName { get; set; }
public string PermissionDescription { get; set; }
public bool AllowViewAccess { get; set; }
public bool AllowModifyAccess { get; set; }
}
View:
#model CreateRoleViewModel
#{
var i = 0;
}
<form method="post" asp-action="CreateRole">
<div class="form-group col-6" style="padding-left:0">
<label asp-for="RoleName"></label>
<input asp-for="RoleName" class="form-control" />
<span asp-validation-for="RoleName" class="text-danger"></span>
</div>
<div class="form-group col-6" style="padding-left:0">
<label asp-for="RoleDescription"></label>
<input asp-for="RoleDescription" class="form-control" />
</div>
<div class="form-group ">
<h4>Permissions</h4>
<div class="card">
<div class="card-header">
<input type="checkbox" class="form-check-input p-2" id="selectAll">
<label class="form-check-label" for="selectAll">Select All<span style="font-weight:bold;font-style:italic;"> (This will allow read/write access to ALL selected items.)</span></label>
</div>
</div>
<!--Permissions should go here-->
<div class="card-body border">
#foreach (var item in Model.Permissions)
{
<div class="row" style="border-radius:3px;border-top:2px solid gray;border-bottom:2px solid gray;padding:15px;">
<div class="col-8">
<input type="checkbox" class="form-check-input p-2" id="select">
<input type="hidden" asp-for="#Model.Permissions[i].PermissionName">
<label class="form-check-label" for="select" style="font-weight:bold;">#item.PermissionName</label>
<p style="color:gray;">#item.PermissionDescription</p>
<input type="hidden" asp-for="#Model.Permissions[i].PermissionDescription">
</div>
<div class="col-2">
<input type="checkbox" class="form-check-input p-2" id="readOnly" asp-for="#Model.Permissions[i].AllowViewAccess">
<label class="form-check-label" for="readOnly">View</label>
</div>
<div class="col-2">
<input type="checkbox" class="form-check-input p-2" id="readWrite" asp-for="#Model.Permissions[i].AllowModifyAccess">
<label class="form-check-label" for="readWrite">Modify</label>
</div>
</div>
i++;
}
</div>
<div asp-validation-summary="All" class="text-info"></div>
<button style="background-color: #6987D5;color:white;" class="btn">Save</button>
<button class="btn" style="background-color:lightgray;border:1px solid darkgray">Cancel</button>
</div>
</form>
Controller:
public IActionResult Index()
{
CreateRoleViewModel createRoleViewModel = new CreateRoleViewModel();
return View(createRoleViewModel);
}
//[Route("Administration/Permissions/CreateRole")]
[HttpPost]
[ValidateAntiForgeryToken]
public ActionResult CreateRole(CreateRoleViewModel newRole)
{
try
{
var test = newRole;
return RedirectToAction(nameof(Index));
}
catch
{
return View();
}
}
Result: