I have to implement more than 30 Checkboxes for a Model and I am not sure about the correct way to implement it. Currently I am doing it this way.
I have Model class with more that 30 checkboxes I am not including all of them here Venue.cs
using System;
using System.Collections.Generic;
namespace firstp.Models
{
public class Venue
{
public int Id { get; set; }
public string Name { get; set; }
public string Description {get;set;}
public string Category { get; set; }
public string Address { get; set; }
// Facilities
public bool AirCondition {get;set;}
public bool CableTV {get;set;}
public bool Computer {get;set;}
public bool DVD {get;set;}
public bool UseOfPool {get;set;}
public bool Parking {get;set;}
public bool SmokingAllowed {get;set;}
public bool Internet {get;set;}
public bool Parking {get;set;
public bool Heater {get;set;
public bool Lift {get;set;}
public bool CoffeePot {get;set;}
public bool DishWasher {get;set;}
//Activities
public bool Concerts {get;set;}
public bool LiveShow {get;set;}
public bool Party {get;set;}
public bool Swimming {get;set;}
public bool Wedding {get;set;}
public bool Birthday {get;set;}
}
}
I am binding all the Properties of Checkbox one by one in Create.cshtml
#model Venue
<form asp-action="Create" asp-controller="Owner" method="POST">
<input type="hidden" asp-for="Id"/>
<input type="text" asp-for="Name"/>
<input type="text" asp-for="Description"/>
<input type="text" asp-for="Category"/>
<input type="text" asp-for="Address"/>
<ul class="facilities">
<li class="checkbox"><input type="checkbox" asp-for="AirCondition">Air conditioning </li>
<li class="checkbox"><input type="checkbox" asp-for="CableTV"> Cable </li>
<li class="checkbox"><input type="checkbox" asp-for="Computer" >Computering </li>
<li class="checkbox"><input type="checkbox" asp-for="DVD"> DVD </li>
<li class="checkbox"><input type="checkbox" asp-for="UseOfPool" > Use Of Pool </li>
<li class="checkbox"><input type="checkbox" asp-for="Parking"> Parking </li>
<li class="checkbox"><input type="checkbox" asp-for="SmokingAllowed">SmokingAllowed </li>
<li class="checkbox"><input type="checkbox" asp-for="Internet"> Internet </li>
<li class="checkbox"><input type="checkbox" asp-for="Lift">Lift </li>
<li class="checkbox"><input type="checkbox" asp-for="CoffeePot"> CoffeePot </li>
<li class="checkbox"><input type="checkbox" asp-for="DishWasher"> DishWasher </li>
<li class="checkbox"><input type="checkbox" asp-for="Parking"> Parking</li>
<li class="checkbox"><input type="checkbox" asp-for="Heater"> Heater</li>
</ul>
<ul class="activities">
<li class="checkbox"><input type="checkbox" asp-for="Concerts"> Concerts > </li>
<li class="checkbox"><input type="checkbox" asp-for="LoveShow"> LiveShow </li>
<li class="checkbox"><input type="checkbox" asp-for="Swimming" > Swimming </li>
<li class="checkbox"><input type="checkbox" asp-for="Party"> Party </li>
<li class="checkbox"><input type="checkbox" asp-for="Wedding" > Wedding </li>
<li class="checkbox"><input type="checkbox" asp-for="Birthday"> Birthday </li>
</ul>
<input type="submit" value="Save">
</form>
VenueController.cs
public async Task<IActionResult> Create(Venue v){
_context.Venues.Add(v);
_context.SaveChanges();
return RedirectToAction(nameof(Index));
}
Any thoughts on this. Is this the corect way to implement Multiple Checkbox. If not then how exactly can it be done.
Wrong way.
1) Add new table for Facility. Columns = ID, Name
2) Add new table for Activity. Columns = ID, Name
3) Add new table for Venue's Facility records. Columns = ID, VenueID, FacilityID
4) Add new table for Venue's Activity records. Columns = ID, VenueID, ActivityID
5) Add new 2 partial views in venue's view for facility and activity to load checkboxes. Loop models to bind checkbox.
6) Get data from facility and activity partial views and save data into Venue's Facility and Activity tables.
EDITED for clear explanation with screenshots.
1) Create new table for Facility
2) Create new table for Activity
3) Create new table for VenueFacility (facility records for venue). You need to create relationship between this table, venue table and facility table in SQL Server.
4) Create new table for VenueActivity (activity records for venue). You need to create relationship between this table, venue table and activity table in SQL Server.
5) Re-run Scaffold-DbContext command in tools > nuget > package manager console to update your models and dbcontext.
6) Add new partial view for Facility.
_FacilityList.cshtml
#model List<TestBenchmark.Models.VenueFacility>
#{
var db = new TestContext();
var list = db.Facility.AsQueryable();
int i = 0;
foreach (var item in list)
{
<input type="hidden" asp-for="#Model[i].FacilityId" value="#item.Id" />
<input type="checkbox" asp-for="#Model[i].IsChecked" /> #item.Name
i++;
}
}
7) Add new partial view for Activity.
_ActivityList.cshtml
#model List<TestBenchmark.Models.VenueActivity>
#{
var db = new TestContext();
var list = db.Activity.AsQueryable();
int i = 0;
foreach (var item in list)
{
<input type="hidden" asp-for="#Model[i].ActivityId" value="#item.Id" />
<input type="checkbox" asp-for="#Model[i].IsChecked" /> #item.Name
i++;
}
}
8) Use this code in your venue page
<form method="post" asp-action="Index">
Venue Name: <input type="text" asp-for="Name" />
<br />
Facility<br />
<partial name="_FacilityList" for="#Model.VenueFacility" />
<br /><br />
Activity<br />
<partial name="_ActivityList" for="#Model.VenueActivity" />
<br />
<button>Save</button>
</form>
How page looks like
Result
EDITED 2 for entity classes
Venue.cs
public partial class Venue
{
public Venue()
{
VenueActivity = new HashSet<VenueActivity>();
VenueFacility = new HashSet<VenueFacility>();
}
public int Id { get; set; }
public string Name { get; set; }
public virtual ICollection<VenueActivity> VenueActivity { get; set; }
public virtual ICollection<VenueFacility> VenueFacility { get; set; }
}
Facility.cs
public partial class Facility
{
public Facility()
{
VenueFacility = new HashSet<VenueFacility>();
}
public int Id { get; set; }
public string Name { get; set; }
public virtual ICollection<VenueFacility> VenueFacility { get; set; }
}
Activity.cs
public partial class Activity
{
public Activity()
{
VenueActivity = new HashSet<VenueActivity>();
}
public int Id { get; set; }
public string Name { get; set; }
public virtual ICollection<VenueActivity> VenueActivity { get; set; }
}
VenueFacility.cs
public partial class VenueFacility
{
public int Id { get; set; }
public int? VenueId { get; set; }
public int? FacilityId { get; set; }
public bool IsChecked { get; set; }
public virtual Facility Facility { get; set; }
public virtual Venue Venue { get; set; }
}
VenueActivity.cs
public partial class VenueActivity
{
public int Id { get; set; }
public int? VenueId { get; set; }
public int? ActivityId { get; set; }
public bool IsChecked { get; set; }
public virtual Activity Activity { get; set; }
public virtual Venue Venue { get; set; }
}
UPDATED ON 5 FEB 2020
Venue.cs. Change HashSet to List. Do same for VenueFacility.
public partial class Venue
{
public Venue()
{
VenueActivity = new List<VenueActivity>();
VenueFacility = new List<VenueFacility>();
}
public int Id { get; set; }
public string Name { get; set; }
public virtual ICollection<VenueActivity> VenueActivity { get; set; }
public virtual ICollection<VenueFacility> VenueFacility { get; set; }
}
YourVenueController.cs
public IActionResult Index()
{
var db = new TestContext();
var list = db.Venue.Include(x => x.VenueActivity).Include(x => x.VenueFacility).FirstOrDefault();
return View(list);
}
Related
I've been working on my version of the app made in this tutorial (https://learn.microsoft.com/pl-pl/aspnet/core/data/ef-rp/complex-data-model?view=aspnetcore-5.0&tabs=visual-studio). And I've got question about a connection between two objects. My idea is to add more than one Material to Paczka. I've manage to connect them together but I can add only one Material. So my question is what should I do to be able to connect more than one?
Object Material
public class Material
{
[Key]
public int PaczkaID { get; set; }
public string Name { get; set; }
public string PN { get; set; }
public string Cert { get; set; }
public string Qty { get; set; }
public Paczka Paczka { get; set; }
}
And object Paczka
public class Paczka
{
public int PaczkaID { get; set; }
public string CRS { get; set; }
public string WO { get; set; }
public DateTime StartDate { get; set; }
public DateTime EndDate { get; set; }
public Material Material { get; set; }
}
Here is how I can add Material to Paczka
public class MaterialModel : PageModel
{
private readonly Pasto.Data.PastoContext _context;
public MaterialModel(Pasto.Data.PastoContext context)
{
_context = context;
}
[BindProperty]
public Paczka Paczka { get; set; }
public async Task<IActionResult> OnGetAsync(int? id)
{
if (id == null)
{
return NotFound();
}
Paczka = await _context.Paczkas
.Include(i => i.Material)
.AsNoTracking()
.FirstOrDefaultAsync(m => m.PaczkaID == id);
if (Paczka == null)
{
return NotFound();
}
return Page();
}
public async Task<IActionResult> OnPostAsync(int? id)
{
if (id == null)
{
return NotFound();
}
var paczkaToUpdate = await _context.Paczkas
.Include(i => i.Material)
.FirstOrDefaultAsync(s => s.PaczkaID == id);
if (paczkaToUpdate == null)
{
return NotFound();
}
if (await TryUpdateModelAsync<Paczka>(
paczkaToUpdate,
"Paczka",
i => i.Material))
{
if (String.IsNullOrWhiteSpace(
paczkaToUpdate.Material?.Name))
{
paczkaToUpdate.Material = null;
}
await _context.SaveChangesAsync();
return RedirectToPage("./Index");
}
return Page();
}
}
And HTML
a<form method="post">
<table class="table">
<thead>
<tr>
<th>
<strong>Name</strong>
</th>
<th>
<strong>P/N</strong>
</th>
<th>
<strong>Certificate</strong>
</th>
<th>
<strong>Quantity</strong>
</th>
</tr>
</thead>
<div class="form-group">
<tbody>
<tr>
<td>
<input asp-for="Paczka.Material.Name" class="form-control" />
</td>
<td>
<input asp-for="Paczka.Material.PN" class="form-control" />
</td>
<td>
<input asp-for="Paczka.Material.Cert" class="form-control" />
</td>
<td>
<input asp-for="Paczka.Material.Qty" class="form-control" />
</td>
</tr>
</tbody>
</div>
</table>
<div class="form-group">
<input type="submit" value="Save" class="btn btn-primary" />
<a asp-page="./Index" class="btn btn-danger">Back to List</a>
</div>
I want Paczka to have many Materials. The material should belong only
to one Paczka because I want to create them while creating Paczka
From your description, the Paczka and Materials should be configured one-to-many relationship. In the Paczka class, use List or ICollection to define the navigation property (Material), code like this:
public class Paczka
{
public int PaczkaID { get; set; }
public string CRS { get; set; }
public string WO { get; set; }
public DateTime StartDate { get; set; }
public DateTime EndDate { get; set; }
public List<Material> Material { get; set; }
}
public class Material
{
[Key]
public int PaczkaID { get; set; }
public string Name { get; set; }
public string PN { get; set; }
public string Cert { get; set; }
public string Qty { get; set; }
//the foreign key
public int PaczkaForeignKey { get; set; }
[ForeignKey("PaczkaForeignKey")]
public Paczka Paczka { get; set; }
}
Then, in the View page, you could use #for statement to loop through the Material and display the related data, code like this:
#page
#model RazorPageSample.Pages.MaterialModel
#{
}
<div class="row">
<div class="col-md-4">
<form method="post">
<div asp-validation-summary="ModelOnly" class="text-danger"></div>
<input type="hidden" asp-for="Paczka.PaczkaID" />
<div class="form-group">
<label asp-for="Paczka.CRS" class="control-label"></label>
<input asp-for="Paczka.CRS" class="form-control" />
<span asp-validation-for="Paczka.CRS" class="text-danger"></span>
</div>
#for (var i = 0; i < Model.Paczka.Material.Count; i++)
{
<div class="form-group">
<label asp-for="Paczka.Material[i].PaczkaID" class="control-label"></label>
<input asp-for="Paczka.Material[i].PaczkaID" class="form-control" />
<span asp-validation-for="Paczka.Material[i].PaczkaID" class="text-danger"></span>
</div>
<div class="form-group">
<label asp-for="Paczka.Material[i].Name" class="control-label"></label>
<input asp-for="Paczka.Material[i].Name" class="form-control" />
<span asp-validation-for="Paczka.Material[i].Name" class="text-danger"></span>
</div>
<div class="form-group">
<label asp-for="Paczka.Material[i].Cert" class="control-label"></label>
<input asp-for="Paczka.Material[i].Cert" class="form-control" />
<span asp-validation-for="Paczka.Material[i].Cert" class="text-danger"></span>
</div>
}
<div class="form-group">
<input type="submit" value="Save" class="btn btn-primary" />
</div>
</form>
</div>
</div>
Then, in the Post method, get the update value and insert or update the data to database, screenshot like this:
More detail information about relationships and update related entity, refer the following articles:
Relationships
Configuring One To Many Relationships in Entity Framework Core
Update related data - ASP.NET MVC with EF Core
I current have parent page that properly navigates to a different child page. The Child page has the stand grid of child records- AND it also has 'Create' link to add a new child record.
Under standard Entity Framework Scaffolding the 'Create' page has standard html'dropdown' lists for the fields that are linked to 'lookup' values.
Below are some screen shots:
The Position Details link navigates to the child records:
The Create New Link brings up the standard scaffolded create page:
The PositionId field shows the full list of choices for parent lookup -rather than bringing in parent key default.
Here is code for create page:
For the create page my question is- how can I default that value of PositionID/PositionNbr to be what it would be for all the existing child records on the previous grid page? This should be a standard child record create scenario- where parent key is prepopulated
I am not finding a whole lot of good examples on a google search for how to prepopulate the parent foreign key in the child records -particularly when the creation is on a separate create page.
Hope my question is making sense- thanks in advance ...
Modified- here is code as code
using System;
using System.Collections.Generic;
using System.Linq;
using System.Threading.Tasks;
using Microsoft.AspNetCore.Mvc;
using Microsoft.AspNetCore.Mvc.RazorPages;
using Microsoft.AspNetCore.Mvc.Rendering;
using ThePositionerRazor2.Models;
namespace ThePositionerRazor2.Pages.PositionDetail
{
public class CreateModel : PageModel
{
private readonly ThePositionerRazor2.Models.WorkManagerV4Context _context;
public CreateModel(ThePositionerRazor2.Models.WorkManagerV4Context context)
{
_context = context;
}
public IActionResult OnGet()
{
ViewData["ImportanceId"] = new SelectList(_context.Imp, "ImportanceId", "ImportanceId");
ViewData["Knowdepth"] = new SelectList(_context.Knowdep, "DepthId", "DepthId");
ViewData["PositionId"] = new SelectList(_context.Possummary, "PositionId", "PositionNbr");
ViewData["TimeSpent"] = new SelectList(_context.Timescale, "TimevalId", "TimevalId");
ViewData["Workitem"] = new SelectList(_context.Workhier, "Workitemid", "Workitemid");
return Page();
}
[BindProperty]
public Posdetail Posdetail { 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()
{
if (!ModelState.IsValid)
{
return Page();
}
_context.Posdetail.Add(Posdetail);
await _context.SaveChangesAsync();
return RedirectToPage("./Index");
}
}
}
and
#page
#model ThePositionerRazor2.Pages.PositionDetail.CreateModel
#{
ViewData["Title"] = "Create";
}
<h1>Create</h1>
<h4>Posdetail</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="Posdetail.PositionId" class="control-label"></label>
<select asp-for="Posdetail.PositionId" class ="form-control" asp-items="ViewBag.PositionId"></select>
</div>
<div class="form-group">
<label asp-for="Posdetail.Workitem" class="control-label"></label>
<select asp-for="Posdetail.Workitem" class ="form-control" asp-items="ViewBag.Workitem"></select>
</div>
<div class="form-group">
<label asp-for="Posdetail.TimeSpent" class="control-label"></label>
<select asp-for="Posdetail.TimeSpent" class ="form-control" asp-items="ViewBag.TimeSpent"></select>
</div>
<div class="form-group">
<label asp-for="Posdetail.ImportanceId" class="control-label"></label>
<select asp-for="Posdetail.ImportanceId" class ="form-control" asp-items="ViewBag.ImportanceId"></select>
</div>
<div class="form-group">
<label asp-for="Posdetail.TimeNrmz" class="control-label"></label>
<input asp-for="Posdetail.TimeNrmz" class="form-control" />
<span asp-validation-for="Posdetail.TimeNrmz" class="text-danger"></span>
</div>
<div class="form-group">
<label asp-for="Posdetail.Knowdepth" class="control-label"></label>
<select asp-for="Posdetail.Knowdepth" class ="form-control" asp-items="ViewBag.Knowdepth"></select>
</div>
<div class="form-group">
<label asp-for="Posdetail.Need" class="control-label"></label>
<input asp-for="Posdetail.Need" class="form-control" />
<span asp-validation-for="Posdetail.Need" class="text-danger"></span>
</div>
<div class="form-group">
<label asp-for="Posdetail.TimeCalc" class="control-label"></label>
<input asp-for="Posdetail.TimeCalc" class="form-control" />
<span asp-validation-for="Posdetail.TimeCalc" class="text-danger"></span>
</div>
<div class="form-group">
<label asp-for="Posdetail.Postskval" class="control-label"></label>
<input asp-for="Posdetail.Postskval" class="form-control" />
<span asp-validation-for="Posdetail.Postskval" class="text-danger"></span>
</div>
<div class="form-group">
<label asp-for="Posdetail.Ftetime" class="control-label"></label>
<input asp-for="Posdetail.Ftetime" class="form-control" />
<span asp-validation-for="Posdetail.Ftetime" class="text-danger"></span>
</div>
<div class="form-group">
<label asp-for="Posdetail.Ftesal" class="control-label"></label>
<input asp-for="Posdetail.Ftesal" class="form-control" />
<span asp-validation-for="Posdetail.Ftesal" class="text-danger"></span>
</div>
<div class="form-group">
<label asp-for="Posdetail.Lastupdated" class="control-label"></label>
<input asp-for="Posdetail.Lastupdated" class="form-control" />
<span asp-validation-for="Posdetail.Lastupdated" class="text-danger"></span>
</div>
<div class="form-group">
<input type="submit" value="Create" class="btn btn-primary" />
</div>
</form>
</div>
</div>
<div>
<a asp-page="Index">Back to List</a>
</div>
#section Scripts {
#{await Html.RenderPartialAsync("_ValidationScriptsPartial");}
}
addtional info:
The relevant models
using System;
using System.Collections.Generic;
namespace ThePositionerRazor2.Models
{
public partial class Possummary
{
public Possummary()
{
Posdetail = new HashSet<Posdetail>();
}
public int PositionId { get; set; }
public string PositionNbr { get; set; }
public string WorkTitle { get; set; }
public string Purpose { get; set; }
public double? JobValue { get; set; }
public double? TimeTotal { get; set; }
public double? Fte { get; set; }
public double? Salary { get; set; }
public DateTime? Lastupdated { get; set; }
public string JobFamily { get; set; }
public int? DescriptionTypeId { get; set; }
public virtual Descriptiontype DescriptionType { get; set; }
public virtual ICollection<Posdetail> Posdetail { get; set; }
}
}
and
using System;
using System.Collections.Generic;
namespace ThePositionerRazor2.Models
{
public partial class Posdetail
{
public int PosdetailId { get; set; }
public int PositionId { get; set; }
public int Workitem { get; set; }
public int? TimeSpent { get; set; }
public int? ImportanceId { get; set; }
public double? TimeNrmz { get; set; }
public int? Knowdepth { get; set; }
public int? Need { get; set; }
public int? TimeCalc { get; set; }
public double? Postskval { get; set; }
public double? Ftetime { get; set; }
public double? Ftesal { get; set; }
public DateTime Lastupdated { get; set; }
public virtual Imp Importance { get; set; }
public virtual Knowdep KnowdepthNavigation { get; set; }
public virtual Possummary Position { get; set; }
public virtual Timescale TimeSpentNavigation { get; set; }
public virtual Workhier WorkitemNavigation { get; set; }
}
}
Confirmation of your requirement:
In your main Index page,you have a List Possummary.When you click the Details link,it will display the details of list Posdetail which belongs to the Possummary you choose in Details page.Then you click the Create link, it will display the Possummary's PositionId which you choose at the begining in Create page.
To meet your requirement:
You could pass the PositionId in the Create link.Then set the default selected value for selectlist by this PositionId:
public IActionResult OnGet(int PositionID)
{
ViewData["ImportanceId"] = new SelectList(_context.Imp, "ImportanceId", "ImportanceId");
ViewData["Knowdepth"] = new SelectList(_context.Knowdep, "DepthId", "DepthId");
//change here....
ViewData["PositionId"] = new SelectList(_context.Possummary, "PositionId", "PositionNbr", PositionID);
ViewData["TimeSpent"] = new SelectList(_context.Timescale, "TimevalId", "TimevalId");
ViewData["Workitem"] = new SelectList(_context.Workhier, "Workitemid", "Workitemid");
return Page();
}
The whole working demo:
Model:
public class Possummary
{
public Possummary()
{
Posdetail = new HashSet<Posdetail>();
}
[Key]
public int PositionId { get; set; }
public string PositionNbr { get; set; }
public string WorkTitle { get; set; }
public string Purpose { get; set; }
public double? JobValue { get; set; }
public double? TimeTotal { get; set; }
public double? Fte { get; set; }
public double? Salary { get; set; }
public DateTime? Lastupdated { get; set; }
public string JobFamily { get; set; }
public int? DescriptionTypeId { get; set; }
public virtual Descriptiontype DescriptionType { get; set; }
public virtual ICollection<Posdetail> Posdetail { get; set; }
}
public class Descriptiontype
{
public int Id { get; set; }
public string Name { get; set; }
}
public partial class Posdetail
{
public int PosdetailId { get; set; }
public int PositionId { get; set; }
public int Workitem { get; set; }
public int? TimeSpent { get; set; }
public int? ImportanceId { get; set; }
public double? TimeNrmz { get; set; }
public int? Knowdepth { get; set; }
public int? Need { get; set; }
public int? TimeCalc { get; set; }
public double? Postskval { get; set; }
public double? Ftetime { get; set; }
public double? Ftesal { get; set; }
public DateTime Lastupdated { get; set; }
public virtual Imp Importance { get; set; }
public virtual Knowdep KnowdepthNavigation { get; set; }
public virtual Possummary Position { get; set; }
public virtual Timescale TimeSpentNavigation { get; set; }
public virtual Workhier WorkitemNavigation { get; set; }
}
public class Imp
{
[Key]
public int ImportanceId { get; set; }
public string Name { get; set; }
}
public class Knowdep
{
[Key]
public int DepthId { get; set; }
public string Name { get; set; }
}
public class Timescale
{
[Key]
public int TimevalId { get; set; }
public string Name { get; set; }
}
public class Workhier
{
[Key]
public int Workitemid { get; set; }
public string Name { get; set; }
}
Possummarys/Index.cshtml:
#page
#model IndexModel
<h1>Index</h1>
<p>
<a asp-page="Create">Create New</a>
</p>
<table class="table">
<thead>
<tr>
<th>
#Html.DisplayNameFor(model => model.Possummary[0].PositionNbr)
</th>
<th>
#Html.DisplayNameFor(model => model.Possummary[0].WorkTitle)
</th>
<th>
#Html.DisplayNameFor(model => model.Possummary[0].Purpose)
</th>
<th></th>
</tr>
</thead>
<tbody>
#foreach (var item in Model.Possummary) {
<tr>
<td>
#Html.DisplayFor(modelItem => item.PositionNbr)
</td>
<td>
#Html.DisplayFor(modelItem => item.WorkTitle)
</td>
<td>
#Html.DisplayFor(modelItem => item.Purpose)
</td>
<td>
<a asp-page="./Edit" asp-route-id="#item.PositionId">Edit</a> |
<a asp-page="./Details" asp-route-id="#item.PositionId">Details</a> |
<a asp-page="./Delete" asp-route-id="#item.PositionId">Delete</a>
</td>
</tr>
}
</tbody>
Possummarys/Index.cshtml.cs:
namespace RazorProj3_1.Pages.Possummarys
{
public class IndexModel : PageModel
{
private readonly RazorProj3_1Context _context;
public IndexModel(RazorProj3_1Context context)
{
_context = context;
}
public IList<Possummary> Possummary { get;set; }
public async Task OnGetAsync()
{
Possummary = await _context.Possummary.ToListAsync();
}
}
}
Possummarys/Details.cshtml:
#page
#model DetailsModel
//focus here...
<a asp-page="/PositionDetail/Create" asp-route-PositionID="#Model.Posdetail[0].PositionId" >Create New</a>
<h1>Postition Detail</h1>
<table class="table">
<thead>
<tr>
<th>
#Html.DisplayNameFor(model => model.Posdetail[0].Position)
</th>
<th>
#Html.DisplayNameFor(model => model.Posdetail[0].WorkitemNavigation)
</th>
<th>
#Html.DisplayNameFor(model => model.Posdetail[0].TimeNrmz)
</th>
<th>
#Html.DisplayNameFor(model => model.Posdetail[0].Importance)
</th>
<th>
#Html.DisplayNameFor(model => model.Posdetail[0].Lastupdated)
</th>
<th></th>
</tr>
</thead>
<tbody>
#foreach (var item in Model.Posdetail)
{
<tr>
<td>
#Html.DisplayFor(modelItem => item.Position.PositionNbr)
</td>
<td>
#Html.DisplayFor(modelItem => item.WorkitemNavigation.Workitemid)
</td>
<td>
#Html.DisplayFor(modelItem => item.TimeNrmz)
</td>
<td>
#Html.DisplayFor(modelItem => item.ImportanceId)
</td>
<td>
#Html.DisplayFor(modelItem => item.Lastupdated)
</td>
<td>
<a asp-page="./Edit" asp-route-id="#item.PosdetailId">Edit</a> |
<a asp-page="./Details" asp-route-id="#item.PosdetailId">Details</a> |
<a asp-page="./Delete" asp-route-id="#item.PosdetailId">Delete</a>
</td>
</tr>
}
</tbody>
</table>
Possummarys/Details.cshtml.cs:
public class DetailsModel : PageModel
{
private readonly RazorProj3_1Context _context;
public DetailsModel(.RazorProj3_1Context context)
{
_context = context;
}
public IList<Posdetail> Posdetail { get; set; }
public async Task<IActionResult> OnGetAsync(int? id)
{
Posdetail = await _context.Posdetail.Include(p=>p.Position)
.Include(p=>p.WorkitemNavigation)
.Where(a=>a.PositionId==id).ToListAsync();
return Page();
}
}
PositionDetail/Create.cshtml: (the same as what you provided)
#page
#model CreateModel
#{
ViewData["Title"] = "Create";
}
<h1>Create</h1>
<h4>Posdetail</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="Posdetail.PositionId" class="control-label"></label>
<select asp-for="Posdetail.PositionId" class="form-control" asp-items="ViewBag.PositionId"></select>
</div>
<div class="form-group">
<label asp-for="Posdetail.Workitem" class="control-label"></label>
<select asp-for="Posdetail.Workitem" class="form-control" asp-items="ViewBag.Workitem"></select>
</div>
<div class="form-group">
<label asp-for="Posdetail.TimeSpent" class="control-label"></label>
<select asp-for="Posdetail.TimeSpent" class="form-control" asp-items="ViewBag.TimeSpent"></select>
</div>
<div class="form-group">
<label asp-for="Posdetail.ImportanceId" class="control-label"></label>
<select asp-for="Posdetail.ImportanceId" class="form-control" asp-items="ViewBag.ImportanceId"></select>
</div>
<div class="form-group">
<label asp-for="Posdetail.TimeNrmz" class="control-label"></label>
<input asp-for="Posdetail.TimeNrmz" class="form-control" />
<span asp-validation-for="Posdetail.TimeNrmz" class="text-danger"></span>
</div>
<div class="form-group">
<label asp-for="Posdetail.Knowdepth" class="control-label"></label>
<select asp-for="Posdetail.Knowdepth" class="form-control" asp-items="ViewBag.Knowdepth"></select>
</div>
<div class="form-group">
<label asp-for="Posdetail.Need" class="control-label"></label>
<input asp-for="Posdetail.Need" class="form-control" />
<span asp-validation-for="Posdetail.Need" class="text-danger"></span>
</div>
<div class="form-group">
<label asp-for="Posdetail.TimeCalc" class="control-label"></label>
<input asp-for="Posdetail.TimeCalc" class="form-control" />
<span asp-validation-for="Posdetail.TimeCalc" class="text-danger"></span>
</div>
<div class="form-group">
<label asp-for="Posdetail.Postskval" class="control-label"></label>
<input asp-for="Posdetail.Postskval" class="form-control" />
<span asp-validation-for="Posdetail.Postskval" class="text-danger"></span>
</div>
<div class="form-group">
<label asp-for="Posdetail.Ftetime" class="control-label"></label>
<input asp-for="Posdetail.Ftetime" class="form-control" />
<span asp-validation-for="Posdetail.Ftetime" class="text-danger"></span>
</div>
<div class="form-group">
<label asp-for="Posdetail.Ftesal" class="control-label"></label>
<input asp-for="Posdetail.Ftesal" class="form-control" />
<span asp-validation-for="Posdetail.Ftesal" class="text-danger"></span>
</div>
<div class="form-group">
<label asp-for="Posdetail.Lastupdated" class="control-label"></label>
<input asp-for="Posdetail.Lastupdated" class="form-control" />
<span asp-validation-for="Posdetail.Lastupdated" class="text-danger"></span>
</div>
<div class="form-group">
<input type="submit" value="Create" class="btn btn-primary" />
</div>
</form>
</div>
</div>
<div>
<a asp-page="Index">Back to List</a>
</div>
#section Scripts {
#{await Html.RenderPartialAsync("_ValidationScriptsPartial");}
}
PositionDetail/Create.cshtml.cs:
public class CreateModel : PageModel
{
private readonly RazorProj3_1Context _context;
public CreateModel(RazorProj3_1Context context)
{
_context = context;
}
public IActionResult OnGet(int PositionID)
{
ViewData["ImportanceId"] = new SelectList(_context.Imp, "ImportanceId", "ImportanceId");
ViewData["Knowdepth"] = new SelectList(_context.Knowdep, "DepthId", "DepthId");
//change here....
ViewData["PositionId"] = new SelectList(_context.Possummary, "PositionId", "PositionNbr", PositionID);
ViewData["TimeSpent"] = new SelectList(_context.Timescale, "TimevalId", "TimevalId");
ViewData["Workitem"] = new SelectList(_context.Workhier, "Workitemid", "Workitemid");
return Page();
}
[BindProperty]
public Posdetail Posdetail { get; set; }
public async Task<IActionResult> OnPostAsync()
{
//the same as yours...
}
}
Result:
I'm looping through a list to populate my questionnaire with selects. I haven't found any tutorial explaining how to extract values from multiple selects in one click. Any ideas?
Here's the view:
<div class="text-center">
<form method="post" asp-page-handler="Answer">
#foreach (var question in Model.QuestionList)
{
<p>#question.Query</p>
<select asp-for="Answer">
<option value="">Select a number</option>
<option value="#question.Option1">#question.Option1</option>
<option value="#question.Option2">#question.Option2</option>
<option value="#question.Option3">#question.Option3</option>
</select>
}
<br>
<br>
<button type="submit">Send</button>
</form>
</div>
Here's the .cs
using System;
using System.Collections.Generic;
using System.Linq;
using System.Threading.Tasks;
using Microsoft.AspNetCore.Mvc;
using Microsoft.AspNetCore.Mvc.RazorPages;
using myquiz.Models;
using myquiz.Services;
namespace myquiz.Pages
{
public class QuizModel : PageModel
{
[ViewData]
[BindProperty]
public string Name { get; set; }
[BindProperty]
public Visitor Visitor { get; set; }
[BindProperty]
public List<Question> QuestionList { get; set; }
public string Answer { get; set; }
public void OnGet()
{
///QuestionList = new List<Question>();
// if (QuestionList is null)
// QuestionList = new List<Question>();
}
public void OnPost()
{
Name = Visitor.Name;
var quizService = new QuizService();
QuestionList = quizService.GetQuestions();
}
public void OnPostAnswer() {
Console.WriteLine("Yay, Answer works");
}
}
}
Here's the model
namespace myquiz.Models
{
public class Question
{
public int Id { get; set; }
public string Query { get; set; }
public string Option1 { get; set; }
public string Option2 { get; set; }
public string Option3 { get; set; }
public string Answer { get; set; }
}
}
Here are two ways to get the select answers:
The first way
All the select lists have the same name Answer,so you could receive an array named Answer in the backend and use BindProperty to bind the values:
public class IndexModel : PageModel
{
[ViewData]
[BindProperty]
public string Name { get; set; }
[BindProperty]
public List<Question1> QuestionList { get; set; }
[BindProperty]
public string[] Answer { get; set; } //modify this...
public void OnPostAnswer()
{
Console.WriteLine("Yay, Answer works");
}
}
View(be the same as yours):
<div class="text-center">
<form method="post" asp-page-handler="Answer">
#foreach (var question in Model.QuestionList)
{
<p>#question.Query</p>
<select asp-for="Answer">
<option value="">Select a number</option>
<option value="#question.Option1">#question.Option1</option>
<option value="#question.Option2">#question.Option2</option>
<option value="#question.Option3">#question.Option3</option>
</select>
}
<br>
<br>
<button type="submit">Send</button>
</form>
</div>
Result:
The second way:
If you want to get the question id with selected answer in QuestionList,you need learn how does model binding system work firstly:
For each property of the complex type, model binding looks through the sources for the name pattern prefix.property_name. If nothing is found, it looks for just property_name without the prefix.For QuestionList is a List,you need give the name like:QuestionList[index].Answer.
<div class="text-center">
<form method="post" asp-page-handler="Answer">
#{
int i = 0;
} //add this...
#foreach (var question in Model.QuestionList)
{
<input hidden asp-for="QuestionList[i].Id" /> //add this..
<p>#question.Query</p>
<select asp-for="QuestionList[i].Answer"> //change asp-for
<option value="">Select a number</option>
<option value="#question.Option1">#question.Option1</option>
<option value="#question.Option2">#question.Option2</option>
<option value="#question.Option3">#question.Option3</option>
</select>
i++; //add this...
}
<br>
<br>
<button type="submit">Send</button>
</form>
</div>
Result:
Update:
Change <select asp-for="Answer"> to:
<select name="Answer">
//..
</select>
Result:
So i am in the process of creating my 3rd crud service inside my webapp. the webapp is running .net core 3.0. my 2 previous crud apps where project and employee. so a user/employee does some work on a project.
so for my 'work' crud service/application in my creation view I need to have a dropdown of all projects and a dropdown for all employees and a view inputs. for employee and project the id is a guid because its unique. But i am seem to having an issue that my modelstateis always invalid.
ps: also my data model so to say it doesn't make any foreign keys for example project id with work id or employee id."
model for work:
public class Work
{
public int Id { get; set; }
[Required]
[StringLength(512, ErrorMessage = "Description cannot exceed 512 characters!")]
public string Description { get; set; }
[Required]
[Display(Name = "Working hours")]
public double WorkingHours { get; set; }
[Required]
[Display(Name = "Employee")]
public Guid EmployeeId { get; set; }
public Employee Employee { get; set; }
[Required]
[Display(Name = "Project")]
public Guid ProjectId { get; set; }
public Projects Project { get; set; }
[Required]
public DateTime dateAdded { get; set; }
}
viewmodel:
public class WorkViewModel
{
public IEnumerable<Projects> projects { get; set; }
public IEnumerable<Employee> employees { get; set; }
public Guid employeeId { get; set; }
public Guid projectId { get; set; }
public Work work { get; set; }
}
create view:
#model TimeSheetTool.ViewModels.WorkViewModel
#{
ViewData["Title"] = "Create";
}
<h1>Create</h1>
<div class="row">
<div class="col-sm-4">
<form asp-action="Save">
<div asp-validation-summary="ModelOnly" class="text-danger"></div>
<div class="form-group">
<select asp-for="projectId" asp-items="#(new SelectList(Model.projects, "Id", "Name"))">
<option>Please select one!</option>
</select>
<span asp-validation-for="projectId" class="text-danger"></span>
</div>
<div class="form-group">
<label asp-for="work.Description" class="control-labels"></label>
<input asp-for="work.Description" class="form-control" />
<span asp-validation-for="work.Description" class="text-danger"></span>
</div>
<div class="form-group">
<label asp-for="work.WorkingHours" class="control-labels"></label>
<input asp-for="work.WorkingHours" class="form-control" />
<span asp-validation-for="work.WorkingHours"></span>
</div>
<div class="form-group">
<select asp-for="employeeId" asp-items="#(new SelectList(Model.employees, "Id", "Name"))">
<option>Please select one!</option>
</select>
<span asp-validation-for="employeeId" class="text-danger"></span>
</div>
<div class="form-group">
<input type="submit" value="Create" class="btn btn-outline-primary" />
</div>
</form>
</div>
</div>
<div>
<a asp-action="Index">Back to List</a>
</div>
What am I doing wrong with this? as you can see in the create view for select list I have got Id i assume it would actually need guid since i'm using guid but then the app won't work at all.
It is because of the Work property in the view model.
public Work work { get; set; }
It has validation, which if not satisfied will cause the invalid model state issue
Add the necessary properties to the view model
public class WorkViewModel {
public IEnumerable<Projects> projects { get; set; }
public IEnumerable<Employee> employees { get; set; }
public Guid employeeId { get; set; }
public Guid projectId { get; set; }
[StringLength(512, ErrorMessage = "Description cannot exceed 512 characters!")]
public string Description { get; set; }
[Display(Name = "Working hours")]
public double WorkingHours { get; set; }
}
and populate them as needed when invoking the action to bind the view
<div class="form-group">
<label asp-for="Description" class="control-labels"></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="WorkingHours" class="control-labels"></label>
<input asp-for="WorkingHours" class="form-control" />
<span asp-validation-for="WorkingHours"></span>
</div>
The values can be copied over to the model on post
I have following html form
<input type="hidden" name="JsonCustomers" data-bind="value: ko.toJSON(customers)" />
<input type="hidden" name="JsonMaterials" data-bind="value: ko.toJSON(materials)" />
<button type="submit" class="btn btn-sm btn-primary">Submit</button>
and input model class
public class SubmitViewModel
{
public string JsonCustomers { get; set; }
public string JsonMaterials { get; set; }
}
Controller action
[HttpPost]
public IActionResult Submit(SubmitViewModel model)
{
throw new NotImplementedException();
}
it is possible to automap Json into something like this ?
public class SubmitViewModel
{
public IEnumerable<InputCustomer> Customers { get; set; }
public IEnumerable<InputMaterial> Materials { get; set; }
}
I would like to skip conversion step from the Json into collection and ideally use data annotations with ModelState.IsValid function. Any idea ?
UPDATE
html
<input type="hidden" name="JsonCustomers" data-bind="value: ko.toJSON(customers)" />
<input type="hidden" name="JsonMaterials" data-bind="value: ko.toJSON(materials)" />
<input type="hidden" name="Customers" data-bind="value: ko.toJSON(customers)" />
<input type="hidden" name="Materials" data-bind="value: ko.toJSON(materials)" />
content of JsonCustomers after form submit
[{"isChecked":true,"name":"CompanyA","volume":"80","expectedDateOfOrder":"1.1.2018"},{"isChecked":true,"name":"CompanyB","volume":"100","expectedDateOfOrder":"2.2.2018"},{"isChecked":true,"name":"CompanyC","volume":"150","expectedDateOfOrder":"3.3.2018"}]
customer class
public class Customer
{
public bool? IsChecked { get; set; }
public string Name { get; set; }
public string Volume { get; set; }
public string ExpectedDateOfOrder { get; set; }
}
the issue is that public IEnumerable<Customer> Customers collection has Count = 0, i dont know why.
this is from FormCollection
With help from #Alex Riabov and based on this discussion https://github.com/aspnet/Mvc/issues/5760
model.Customers = JsonConvert.DeserializeObject<IEnumerable<InputCustomer>>(model.JsonCustomers);
in the controller action did the trick.