How to Change a Single Select Dropdown to a Multi-Select Dropdown? - asp.net

Still in learning stages and want to learn how to create a multi-select dropdown.
I currently have a single select dropdown working. Here is the code for that:
Snip from Municipality Model:
[Display(Name = "Associated Agencies")]
public string? AssocAgencies { get; set; }
Snip from Municipality Create.cs:
public class CreateModel : PageModel
{
private readonly ApplicationDbContext _db;
public Municipality Municipality { get; set; }
public CreateModel(ApplicationDbContext db)
{
_db = db;
}
public IEnumerable<Agency> DisplayAgencyData { get; set; }
public async Task OnGet()
{
await _db.Agency.Select(a => a.AgencyName).ToListAsync();
DisplayAgencyData = await _db.Agency.ToListAsync();
}
public async Task<IActionResult> OnPost()
{
if (ModelState.IsValid)
{
_db.Municipality.Add(Municipality);
await _db.Municipality.AddAsync(Municipality);
await _db.SaveChangesAsync();
TempData["success"] = "Municipality added successfully.";
return RedirectToPage("Index");
}
return Page();
}
Snip from Municipality Create.cshtml:
<table class="table table-bordeless" style="width:100%">
<tr>
<td style="width: 25%">
<div class="mb-3">
<label asp-for="Municipality.AssocAgencies"></label>
<select asp-for="Municipality.AssocAgencies" id="Select2" class="form-select" asp-items="#(new SelectList(Model.DisplayAgencyData.OrderBy(x => x.AgencyName),"AgencyName", "AgencyName"))"><option value="" selected disabled>---Select Agency---</option></select>
</div>
</td>
</tr>
</table>
Values from the Agency model are:
| Id | AgencyName |
|:--:|:--------------------|
|1 |N/A |
|2 |Board of Appeals |
|3 |City Council |
|4 |Planning Board |
|5 |Planning Commission |
|6 |Town Board |
Since I have not done a multi-select before - Is the stored result in the data table cell a comma delimited value?
Ie, if the user selects options 2, 4 and 6 is the value "Board of Appeals, Planning Board, Town Board" OR "2, 4, 6" if someone were to bind the Ids rather than the values?
Also, is there an advantage to doing it this way OR is it more advantageous to have multiple separate single select dropdowns? I'm thinking it could be either way depending on how you wanted to pull the data.
Thanks in advance for your help!

1.If you want to make dropdown multiple you need change string? to List<string>?.
2.Then if you want to pass the Ids instead of name, you need change the second parameter of new SelectList:
new SelectList(Model.DisplayAgencyData.OrderBy(x => x.AgencyName),"Id", "AgencyName")
Whole working demo below
Model:
public class Municipality
{
[Display(Name = "Associated Agencies")]
public List<string>? AssocAgencies { get; set; }
}
public class Agency
{
public int Id { get; set; } //be sure your model contains id property
public string AgencyName { get; set; }
}
Page:
#page
#model CreateModel
<form method="post">
<table class="table table-bordeless" style="width:100%">
<tr>
<td style="width: 25%">
<div class="mb-3">
<label asp-for="Municipality.AssocAgencies"></label>
<select asp-for="Municipality.AssocAgencies" id="Select2" class="form-select" asp-items="#(new SelectList(Model.DisplayAgencyData.OrderBy(x => x.AgencyName),"Id", "AgencyName"))"><option value="" selected disabled>---Select Agency---</option></select>
</div>
</td>
</tr>
</table>
<input type="submit" value="Post"/>
</form>
PageModel:
[BindProperty] //be sure add this....
public Municipality Municipality { get; set; }
public IEnumerable<Agency> DisplayAgencyData { get; set; }
public void OnGet()
{
DisplayAgencyData = await _db.Agency.ToListAsync();
}
public async Task<IActionResult> OnPost()
{
//do your stuff....
}
Note:
If you do not want to change string? to List<string>?, you can add an extra property which receives the multiple selected value and set the value forAssocAgencies by adding Quotes around string in a comma delimited list of strings.
Page:
<form method="post">
<table class="table table-bordeless" style="width:100%">
<tr>
<td style="width: 25%">
<div class="mb-3">
<label asp-for="SelectedAgency"></label>
//don't forget change here asp-for .......
<select asp-for="SelectedAgency" id="Select2" class="form-select" asp-items="#(new SelectList(Model.DisplayAgencyData.OrderBy(x => x.AgencyName),"Id", "AgencyName"))"><option value="" selected disabled>---Select Agency---</option></select>
</div>
</td>
</tr>
</table>
<input type="submit" value="Post"/>
</form>
PageModel:
[BindProperty]
public Municipality Municipality { get; set; }
public IEnumerable<Agency> DisplayAgencyData { get; set; }
[BindProperty]
public List<string> SelectedAgency { get; set; } //add this .
public void OnGet()
{
DisplayAgencyData = await _db.Agency.ToListAsync();
}
public void OnPost()
{
Municipality.AssocAgencies = string.Join(",", SelectedAgency.Select(x => string.Format("'{0}'", x.Replace("'", "''"))));
}

Related

How To Display Multiple Table Column Values in a Single Dropdown on a Razor Page?

I'm not sure of the best way to go about this. I have one table. It is a list of Municipalities and their info. Name, address, phone, fax, email, etc. Right now, there is one row of data for each municipality.
However, each municipality can have multiple agencies. For example, City XYZ might have a City Council, Planning Commission and a Board of Appeals. Currently, I have columns in the Municipality table to hold those values as AssocAgencies1, AssocAgencies2, AssocAgencies3, etc. (So City Council would be in the AssocAgencies1 column, Planning Commission in the AssocAgencies2 column, etc.)
I would like to use this data to populate a table called Referrals. The form to add data to the referrals table wants the Municipality Name and the Agency from that Municipality that the referral is coming from. So, If a user selects City XYZ from a dropdown based on the Municpalities table name column (Municipalities.Name), I would like them then to be able to be provided another FILTERED dropdown that would list any agencies tied to City XYZ (in this example City Council, Planning Commission and a Board of Appeals).
Is it possible to pull those separate columns (Agency1, Agency2, Agency3) into one dropdown? Or should I be combining those agency values into one column as an array (City Council,Planning Commission,Board of Appeals). If that is the case, how would I separate those values into a dropdown (or even radio buttons would work), so that the Referral entry would record just the appropriate agency, not all of them.
Here is my current Municpality model:
namespace Referrals.Model
{
public class Municipality
{
[Key]
public int Id { get; set; }
[Required]
[Display(Name ="SWIS")]
public string SWIS { get; set;}
[Required]
[Display(Name = "Municipality Name")]
public string Name { get; set; }
[Required]
[Display(Name = "Combo Name: Name, Town/City/Village")]
public string ComboName { get; set; }
[Display(Name = "Address 1")]
public string? Addr1 { get; set; }
[Display(Name = "Address 2")]
public string? Addr2 { get; set; }
[Display(Name = "City")]
public string? City { get; set; }
[Display(Name = "State")]
public string? State { get; set; }
[Display(Name = "Zip")]
[DataType(DataType.PostalCode)]
public string? Zip { get; set; }
[Display(Name = "Phone Number")]
[RegularExpression(#"^\(?([1-9]\d{2}-\d{3}-\d{4})$", ErrorMessage = "Not a valid phone number")]
public string? OfficePhone { get; set; }
[Display(Name = "Fax Number")]
[RegularExpression(#"^\(?([1-9]\d{2}-\d{3}-\d{4})$", ErrorMessage = "Not a valid fax number")]
public string? FaxNumber { get; set; }
[Display(Name = "Email Address")]
[DataType(DataType.EmailAddress)]
public string? EmailAddress { get; set; }
[Display(Name = "Website")]
[DataType(DataType.Url)]
public string? Website { get; set; }
[Display(Name = "Associated Agencies")]
public string? AssocAgencies1 { get; set; }
[Display(Name = "Associated Agencies")]
public string? AssocAgencies2 { get; set; }
[Display(Name = "Associated Agencies")]
public string? AssocAgencies3 { get; set; }
[Display(Name = "Associated Agencies")]
public string? AssocAgencies4 { get; set; }
[Display(Name = "Associated Agencies")]
public string? AssocAgencies5 { get; set; }
[Required]
[Display(Name = "Added/Updated By")]
public string UpdatedBy { get; set; }
[Required]
[Display(Name = "Date Added/Updated")]
[DataType(DataType.Date)]
public DateTime UpdateDate { get; set; }
}
}
And here is a snip of the start of my Referral view page:
#page
#model Referrals.Pages.NewReferrals.CreateModel
<form method="post">
<div class="border p-3 mt-4">
<div class="row pb-2">
<h2 class="text-primary pl-3">Add New Referral</h2>
<hr />
</div>
<div asp-validation-summary="All"></div>
<table class="table table-bordeless" style="width:100%">
<tr>
<td style="width: 15%">
<div class="mb-3">
<label asp-for="Referral.RefNo"></label>
<input asp-for="Referral.RefNo" class="form-control"/>
<span asp-validation-for="Referral.RefNo" class="text-danger"></span>
</div>
</td>
<td style="width: 10%">
<div class="mb-3">
<label asp-for="Referral.RefSuffix"></label>
<input asp-for="Referral.RefSuffix" class="form-control" />
<span asp-validation-for="Referral.RefSuffix" class="text-danger"></span>
</div>
</td>
<td style="width: 15%">
<div class="mb-3">
<label asp-for="Referral.RefYear"></label>
<input asp-for="Referral.RefYear" class="form-control" />
<span asp-validation-for="Referral.RefYear" class="text-danger"></span>
</div>
</td>
<td style="width: 15%">
<div class="mb-3">
<label asp-for="Referral.RefNoComplete"></label>
// Need to figure out how to concatenate values for here of RefNo, RefSuffix and RefYear
</div>
</td>
<td style="width: 15%">
<div class="mb-3">
<label asp-for="Referral.DateReceived"></label>
<input asp-for="Referral.DateReceived" type="date" class="form-control" />
<span asp-validation-for="Referral.DateReceived" class="text-danger"></span>
</div>
</td>
<td style="width: 15%">
<div class="mb-3">
<label asp-for="Referral.BoardMtgMonth"></label>
<input asp-for="Referral.BoardMtgMonth" class="form-control" />
<span asp-validation-for="Referral.BoardMtgMonth" class="text-danger"></span>
</div>
</td>
<td style="width: 15%">
<div class="mb-3">
<label asp-for="Referral.BoardMtgYear"></label>
<input asp-for="Referral.BoardMtgYear" class="form-control" />
<span asp-validation-for="Referral.BoardMtgYear" class="text-danger"></span>
</div>
</td>
</tr>
</table>
<table class="table table-bordeless" style="width:100%">
<tr>
<td style="width: 30%">
<div class="mb-3">
<label asp-for="Referral.RefMunicipality"></label>
<select asp-for="Referral.RefMunicipality" id="Select1" class="form-select" asp-items="#(new SelectList(Model.DisplayMuniName.OrderBy(x => x.Name),"Name", "Name"))"><option value="Name" selected disabled>---Select Referring Municipality---</option></select>
</div>
</td>
<td style="width: 25%">
<div class="mb-3">
// Would like a dropdown here filtered on the previous dropdown
<label asp-for="Referral.RefAgencyName"></label>
<input asp-for="Referral.RefAgencyName" class="form-control" />
<span asp-validation-for="Referral.RefAgencyName" class="text-danger"></span>
</div>
</td>
Any suggestions or points in the right direction would be sincerely appreciated.
My .cs for the create view:
using Referrals.Data;
using Microsoft.AspNetCore.Mvc;
using Microsoft.AspNetCore.Mvc.RazorPages;
using Referrals.Model;
using Microsoft.EntityFrameworkCore;
namespace Referrals.Pages.NewReferrals;
[BindProperties]
public class CreateModel : PageModel
{
private readonly ApplicationDbContext _db;
public Referral Referral { get; set; }
public CreateModel(ApplicationDbContext db)
{
_db = db;
}
public IEnumerable<Municipality> DisplayMuniName { get; set; }
public async Task OnGet()
{
await _db.Referral.Select(a => a.RefMunicipality).ToListAsync();
DisplayMuniName = await _db.Municipality.ToListAsync();
}
List<string> GetAgencies(int Id)
{
var result = new List<string>();
var municipality = GetMunicipality(Id);
if (!string.IsNullOrEmpty(municipality.AssocAgencies1))
{
result.Add(municipality.AssocAgencies1);
}
if (!string.IsNullOrEmpty(municipality.AssocAgencies2))
{
result.Add(municipality.AssocAgencies2);
}
if (!string.IsNullOrEmpty(municipality.AssocAgencies3))
{
result.Add(municipality.AssocAgencies3);
}
if (!string.IsNullOrEmpty(municipality.AssocAgencies4))
{
result.Add(municipality.AssocAgencies4);
}
if (!string.IsNullOrEmpty(municipality.AssocAgencies5))
{
result.Add(municipality.AssocAgencies5);
}
//.... add all other agencies
return result;
}
public async Task<IActionResult> OnPost()
{
if (ModelState.IsValid)
{
_db.Referral.Add(Referral);
await _db.Referral.AddAsync(Referral);
await _db.SaveChangesAsync();
TempData["success"] = "Referral added successfully.";
return RedirectToPage("Index");
}
return Page();
}
}
Complete .CS
using Referrals.Data;
using Microsoft.AspNetCore.Mvc;
using Microsoft.AspNetCore.Mvc.RazorPages;
using Referrals.Model;
using Microsoft.EntityFrameworkCore;
namespace Referrals.Pages.NewReferrals;
[BindProperties]
public class CreateModel : PageModel
{
private readonly ApplicationDbContext _db;
private readonly IList<string> _agencies;
public Referral Referral { get; set; }
public CreateModel(ApplicationDbContext db)
{
_db = db;
}
public CreateModel()
{
//.....
_agencies = new List<string>();
}
public IEnumerable<Municipality> DisplayMuniName { get; set; }
public IEnumerable<Calendar> DisplayCalendarMonth { get; set; }
public IEnumerable<string> DisplayAgencyName { get; set; }
public async Task OnGet()
{
// await _db.Referral.Select(a => a.RefMunicipality).ToListAsync();
// DisplayMuniName = await _db.Municipality.ToListAsync();
await _db.Referral.Select(a => a.BoardMtgMonth).ToListAsync();
DisplayCalendarMonth = await _db.Calendar.ToListAsync();
DisplayMuniName = _municipality;
DisplayAgencyName = _agencies;
}
private List<string> FillAgencies(int id)
{
var result = new List<string>();
if (!string.IsNullOrEmpty(municipality.AssocAgencies1))
{
result.Add(municipality.AssocAgencies1);
}
if (!string.IsNullOrEmpty(municipality.AssocAgencies2))
{
result.Add(municipality.AssocAgencies2);
}
if (!string.IsNullOrEmpty(municipality.AssocAgencies3))
{
result.Add(municipality.AssocAgencies3);
}
if (!string.IsNullOrEmpty(municipality.AssocAgencies4))
{
result.Add(municipality.AssocAgencies4);
}
if (!string.IsNullOrEmpty(municipality.AssocAgencies5))
{
result.Add(municipality.AssocAgencies5);
}
return result;
}
public JsonResult OnGetRetrieveAgencies(int id)
{
var agencies = FillAgencies(id);
return new JsonResult(agencies);
}
public async Task<IActionResult> OnPost()
{
if (ModelState.IsValid)
{
_db.Referral.Add(Referral);
await _db.Referral.AddAsync(Referral);
await _db.SaveChangesAsync();
TempData["success"] = "Referral added successfully.";
return RedirectToPage("Index");
}
else
{
//reload the municipality
DisplayMuniName = await _db.Municipality.ToListAsync();
if (Referral.RefMunicipality !=0)
{
//if a municipality was selected reload the agencies
DisplayAgencyName = FillAgencies(Referral.RefMunicipality);
}
}
return Page();
}
}
Add a onChange event handler for when a municipality is selected in the "Select1" drop down list, so that you can perform an ajax call to a GET method on the server that loads the agencies for the selected municipality. It is advisable to perform an ajax call so that you won't have to reload the whole page when selecting a municipality but only a portion of it (the drop down list with agencies). When the server method completes successfully, populate the agencies drop down list on the client side using JavaScript.
You can find multiple examples on how to implement ajax calls with razor pages. This is one
On the server side, create the GET method that returns the list of agencies for the selected municipality. This is being called through ajax. I recommend using municipality Id, not municipality name because ids are unique. Imagine you have London (from UK) and London (from Ohio). They should be differentiated by Id, not by Name.
public async Task<JsonResult> OnGetRetrieveAgencies(int id)
{
//build a list of agencies for the selected municipality
var result = new List<string>();
var municipality = await _db.Municipality.SingleAsync(s=> s.Id == id);
if (!string.IsNullOrEmpty(municipality.AssocAgencies1))
{
result.Add(municipality.AssocAgencies1);
}
if (!string.IsNullOrEmpty(municipality.AssocAgencies2))
{
result.Add(municipality.AssocAgencies2);
}
if (!string.IsNullOrEmpty(municipality.AssocAgencies3))
{
result.Add(municipality.AssocAgencies3);
}
if (!string.IsNullOrEmpty(municipality.AssocAgencies4))
{
result.Add(municipality.AssocAgencies4);
}
if (!string.IsNullOrEmpty(municipality.AssocAgencies5))
{
result.Add(municipality.AssocAgencies5);
}
return new JsonResult(result);
}
On the view, make the following modifications:
use municipality id as value and municipality name as text
<label asp-for="Referral.RefMunicipality"></label>
<select asp-for="Referral.RefMunicipality" id="Select1" class="form-select" asp-items="#(new SelectList(Model.DisplayMuniName.OrderBy(x => x.Name),"Id", "Name"))"><option value="Name" selected disabled>---Select Referring Municipality---</ option></select>
add the agency drop down list
Add auto selection for Agencies drop down list. We modify the select element:
<label asp-for="Referral.RefAgencyName"></label>
<select asp-for="Referral.RefAgencyName" id="SelectAgencies" class="form-control" asp-items="#(new SelectList(Model.DisplayAgencyName.OrderBy(x => x)))"><option value="Name" selected disabled>--Please Select--</option></select>
<span asp-validation-for="Referral.RefAgencyName" class="text-danger"></span>
Add the Scripts section after the closing form element with the JavaScript code that calls the server method and populates the agencies drop down list using jQuery Ajax. I've included some comments inline.
Let's use the agency name for both option text and option value. Remember, this is not ideal but, since we don't have an agency id, lets keep it like this. It helps us with the auto-selection.
#section Scripts {
<script type="text/javascript">
$(document).ready(function () {
$("#Select1").change(function(){
var munId = $("#Select1 :selected").val();
$.ajax({
//the url to call from the server. In this case it is a GET request.
//Razor Pages needs a "handler" query string parameter with the value of the method from the server to be called
//from which you remove the "OnGet" prefix for GET methods or "OnPost" prefix for POST methods
//also add the selected municipality. If we have Id's there are always preferred as opposed to names because they should to be unique.
url: '/NewReferrals/Create?handler=RetrieveAgencies&id='+munId,
type: 'GET',
contentType: "application/json",
dataType: "json"
}).done(function(result) {
//this method gets called if the call to the server was successful
//bind the agencies drop down list here, on the client side, when the result is received from the server
var agenciesDropDown = $('#SelectAgencies');
agenciesDropDown.empty(); //clear the drop down list of the existing data
agenciesDropDown.append($("<option value=''>--Please Select--</option>")); //add default value
//the result is an array of agency names.
// Iterate through the array using jquery's "each" and create options with (0, 'AgencyName 1'), (1, "Agency Name 2") etc
// Here again, we prefer to have the option value numeric (in this case we auto-assign an index 0,1,2..)
// and the option text the actual display name
$.each(result, function(index, value) {
//agenciesDropDown.append($('<option>').text(value).attr('value', index));
agenciesDropDown.append($('<option>').text(value).attr('value', value));
});
}).fail(function (jqXHR, textStatus, errorThrown) {
//this method gets called when there was an error in the response from the server
console.log("error:" + errorThrown);
});
});
});
</script>
}
We will save the agencies on the server side as well to be able to preserve the selection if necessary. That is, if we have errors on the page, which means the ModelState is invalid. For this some refactoring is necessary.
In the code behind, add a new private field in the CreateModel class.
private IList<string> _agencies;
In the constructor initialize the _agencies field:
public CreateModel()
{
//.....
_agencies = new List<string>();
}
Add a public property that will encapsulate the private field:
public IEnumerable<string> DisplayAgencyName
{
get; set;
}
Initialize the property in the OnGet method:
public async Task OnGet()
{
//.....
DisplayMuniName = _municipality;
DisplayAgencyName = _agencies;
}
Extract the code that fills the agencies in a private method. It will be called both from OnGetRetrieveAgencies (through ajax) and OnPost when the ModelState is not valid.
private List<string> FillAgencies(int id)
{
var result = new List<string>();
//....add the rest of the code to fill the agencies
return result;
}
public JsonResult OnGetRetrieveAgencies(int id)
{
var agencies = FillAgencies(id);
return new JsonResult(agencies);
}
Modify the OnPost() method to reload the Municipality and the Agencies drop down lists if the model state is not valid:
public async Task<IActionResult> OnPost()
{
if (ModelState.IsValid)
{
//...code remains the same
}
else
{
//reload the municipality
DisplayMuniName = await _db.Municipality.ToListAsync();
if (Referral.RefMunicipality != 0)
{
//if a municipality was selected reload the agencies
DisplayAgencyName = FillAgencies(Referral.RefMunicipality);
}
}
return Page();
}
EDIT 2
Remove second CreateModel(). Leave only the one that you have with ApplicationDbContext
In OnGet, uncomment your await _db.Referral.. line and remove the last two lines.
Before the end of the method add DisplayAgencyName = new List<string>();
Modify FillAgencies signature to be like this:
private async Task<List<string>> FillAgencies(int id)
{
var result = new List<string>();
var municipality = await _db.Municipality.SingleAsync(s => s.Id == id);
//...add the code for filling the agencies
return result;
}
OnGetRetrieveAgencies should look like this
public async Task<JsonResult> OnGetRetrieveAgencies(int id)
{
var agencies = await FillAgencies(id);
return new JsonResult(agencies);
}
In the OnPost method add an await keyword
//if a municipality was selected reload the agencies
DisplayAgencyName = await FillAgencies(Referral.RefMunicipality);

Handling the field that is not in the DB in the MVC

I am building an Product Ordering web application I have used Entity Framework to Scaffold-DbContext to Scaffold the Tables in the DB to the Model Classes. I have table called Inventory in the DB and now the view is created in the .Net Core project that shows the list of the inventory in the DB like below
I am trying to add a new field called QuantityRequired in the Model class that is not needed to be on the the Database. On the view I am trying to make this an input field so the users can enter the no.of items required and click Buy Now that add the item into the cart
public partial class Inventory
{
public string StrainId { get; set; }
public string StrainName { get; set; }
public string StrainCode { get; set; }
public string Age { get; set; }
public string Sex { get; set; }
public string Genotype { get; set; }
public int QuantityAvailable { get; set; }
public string RoomNumber { get; set; }
public int InventoryId { get; set; }
[NotMapped]
public int QuantityRequired { get; set; }
}
Upon reading I found that the [NotMapped] attribute helps with this, so updated the model class like above and the view is now like
<td >
<input id="Text3" type="text" asp-for="#item.QuantityReq" />
</td>
<td>
<a asp-controller="cart" asp-action="buy" asp-route-customerID="#custID.CustomerId" asp-route-invetoryID="#item.InventoryId">Buy Now</a>
</td>
Now it shows the new field in the table
I did not do anything on the Controller of the Inventory Page.Should I bind this value in the controller? Because when the button Buy Now is clicked I have the below code on the CartController
public IActionResult Index()
{
var cart = SessionHelper.GetObjectFromJson<List<Item>>(HttpContext.Session, "cart");
ViewBag.cart = cart;
return View();
}
[Route("buy/{customerID}/{invetoryID}")]
public async Task<IActionResult> Buy(int? customerID, int? inventoryID)
{
if (customerID == null || inventoryID == null)
{
return NotFound();
}
Customer custData = await _context.Customers.FindAsync(customerID);
var intData = await _context.Inventories.FindAsync(invetoryID);
if (SessionHelper.GetObjectFromJson<List<Item>>(HttpContext.Session, "cart") == null)
{
List<Item> cart = new List<Item>();
cart.Add(new Item
{
Custom = custData,
Inventory = intData,
**Quantity = intData.QuantityReq**
});
SessionHelper.SetObjectAsJson(HttpContext.Session, "cart", cart);
}
return RedirectToAction("Index");
}
}
I tried to retrieve the QuantityReq from the Quantity = intData.QuantityReq but it shows '0' and not the value that was entered by the users
Cart View page is like
#foreach (var item in ViewBag.cart)
{
<tr>
<td>#item.Inventory.StrainId</td>
<td>#item.Inventory.StrainName</td>
<td>#item.Inventory.StrainCode</td>
<td>#item.Inventory.Age</td>
<td>#item.Inventory.Sex</td>
<td>#item.Quantity</td>
</tr>
}
How to pass the user entered value from the Inventory page into the Cart page
You're not sending the quantity to the Controller for it to process when performing the Buy.
Instead, you're retrieving an object "intData" from the database (which clearly will not have the value that you just entered in the UI), and then trying to use Quantity from that intData to populate an item in the cart.
You need to add quantity as a parameter on your controller method, send the value from the UI, and then use that parameter when creating the cart item:
Client UI:
<td >
<input id="Text3" type="text" asp-for="#item.QuantityReq" />
</td>
<td>
<a asp-controller="cart"
asp-action="buy"
asp-route-customerID="#custID.CustomerId"
asp-route-invetoryID="#item.InventoryId"
asp-route-quantity="#item.QuantityReq">Buy Now</a>
</td>
Controller:
[Route("buy/{customerID}/{invetoryID}/{quantityReq}")]
public async Task<IActionResult> Buy(int? customerID, int? invetoryID, int quantityReq)
{
if (customerID == null || invetoryID == null)
{
return NotFound();
}
Customer custData = await _context.Customers.FindAsync(customerID);
var intData = await _context.Inventories.FindAsync(invetoryID);
if (SessionHelper.GetObjectFromJson<List<Item>>(HttpContext.Session, "cart") == null)
{
List<Item> cart = new List<Item>();
cart.Add(new Item
{
Custom = custData,
Inventory = intData,
Quantity = quantityReq
});
SessionHelper.SetObjectAsJson(HttpContext.Session, "cart", cart);
}
return RedirectToAction("Index");
}
this code was tested in Visual Studio
#foreach (var item in ViewBag.cart)
{
<tr>
<td>#item.Inventory.StrainId</td>
<td>#item.Inventory.StrainName</td>
<td>#item.Inventory.StrainCode</td>
<td>#item.Inventory.Age</td>
<td>#item.Inventory.Sex</td>
<td>#item.Quantity</td>
<td>
<form method="post"
asp-controller="cart"
asp-action="buy">
<row>
<column>
<input type="text" id="quantityReq" name="quantityReq" value = #item.QuantityReq/>
</column>
<column>
<input type="hidden" id="customerID" name="customerID" value = "#custID.CustomerId" />
<input type="hidden" id="invetoryID" name="invetoryID" value = "#item.InventoryId" />
<button type="submit" style="border:none; background-color:transparent"> <u> Buy now</u> </button>
</column>
</row>
</form>
</td>
</tr>
}
and remove [Route("buy/{customerID}/{invetoryID}/{quantityReq}")] from action
public async Task<IActionResult> Buy(int customerID, int invetoryID, int quantityReq)

How to take value from Select/Option and inserted into href

I need help if it is possible. I have a list of classrooms, as it is in the picture below. I want to list all teachers in the "select option" and when the user selects the teacher he can click save and the classroom will be updated, as it is in the href. How can I take the value after the foreach loop?
<select id="teachers">
#foreach(var teacher in #Model.Teachers){
<option value="#teacher.Id">#teacher.Id</option>
}
</select>
<a asp-controller="Classroom" asp-action="Update" asp-route-teacherId=""></a>
<a asp-controller="Classroom" asp-action="Update" asp-route-teacherId="XX">Save</a>
First, for the above a tag helper, the generated HTML like this:
Save
or
Save
Besides, to update teachers in specific classrooms, you should also submit the classroom id to the Update action method, so, the generated URL should have multiple parameters(teacherid and classroomId), like this: Save
More detail information, see Anchor Tag Helper.
I have a list of classrooms, as it is in the picture below. I want to
list all teachers in the "select option" and when the user selects the
teacher he can click save and the classroom will be updated, as it is
in the href. How can I take the value after the foreach loop?
From your description, each classroom (row) should have a <select> element to choose the teacher and a "Save" button to update the current row update, right?
In this scenario, you could use the select element's change event to get the selected value, and then update the <a> tag href attribute.
You can refer the following sample:
Model:
public class ClassRoom
{
public int ID { get; set; }
public string Classroom { get; set; }
public string SubJect { get; set; }
public string Teacher { get; set; }
public DateTime Date { get; set; }
}
public class Teacher
{
public int Id { get; set; }
public string Name { get; set; }
}
public class Subject
{
public int Id { get; set; }
public string SubjectName { get; set; }
}
public class ClassRoomViewModel
{
public List<ClassRoom> ClassRooms { get; set; }
public List<Teacher> Teachers { get; set; }
public List<Subject> Subjects { get; set; }
}
Controller:
public class ClassRoomController : Controller
{
public IActionResult Index()
{
// you could query the database to get the data. The following is the test data.
var viewmodel = new ClassRoomViewModel();
viewmodel.ClassRooms = new List<ClassRoom>()
{
new ClassRoom(){ ID=1, Classroom="EOIS1", Date=DateTime.Now },
new ClassRoom(){ ID=2, Classroom="EOIS2", Date=DateTime.Now }
};
viewmodel.Teachers = new List<Teacher>()
{
new Teacher(){ Id=101, Name="Tom"},
new Teacher(){ Id=102, Name="Jack"}
};
return View(viewmodel);
}
public IActionResult Update(int teacherId, int classroomid)
{
//update the classroom
//redirect to the Index page and refresh the page.
return RedirectToAction(nameof(Index));
}
}
View Page:
#model MVCWebApplication.Models.ClassRoomViewModel
<table class="table" id="customers" >
<thead>
...
</thead>
<tbody>
#foreach (var item in Model.ClassRooms) {
<tr>
<td>
#Html.DisplayFor(modelItem => item.ID)
</td>
<td>
#Html.DisplayFor(modelItem => item.Classroom)
</td>
<td>
#Html.DisplayFor(modelItem => item.SubJect)
</td>
<td>
<select id="teachers" class="teachers">
<option value="0">select teacher</option>
#foreach (var teacher in #Model.Teachers)
{
<option value="#teacher.Id">#teacher.Name</option>
}
</select>
</td>
<td>
<a asp-controller="ClassRoom" asp-action="Update" asp-route-classroomid="#item.ID" asp-route-teacherId="">Save</a>
</td>
<td>
#Html.DisplayFor(modelItem => item.Date)
</td>
</tr>
}
</tbody>
</table>
#section Scripts{
<script>
$(function () {
$(".teachers").each(function (Index, item) {
$(item).change(function () {
var teacherid = $(this).val(); //get the selected value.
var existinghref = $(item).parent().parent().find("a").attr("href"); //get the hyperlink href attribute.
if (teacherid != 0) {
existinghref = existinghref + "&teacherId=" + teacherid; //add the parameter at the end of the request url.
$(item).parent().parent().find("a").attr("href", existinghref); //update the hyperlink href attribute.
}
else {
alert("Please select teacher"); //show prompt to let user select teacher.
}
});
});
});
</script>
}
The result as below:

how to insert multiple rows database in asp.net core 2.1

I have one table which contains static data with 5 columns and 4 rows. I have another table which would accept input based on static table. I am trying to build a view with table where all field from static Db table is displayed and few text box so that user could fill in the data. But when I click on submit button no data is saved in second table. Can anyone help me with this. How could I submit multiple rows to database based on static database table.
Following are the codes:
View Model:
public class DBM2BillingViewModel
{
public List<DatabaseM2> databaseM2List { get; set; }
[Display(Name = "Items")]
public string Name { get; set; }
[Display(Name = "PO Item No.")]
public int POItemNo { get; set; }
[Display(Name = "Date of Effect")]
public DateTime DateOfEffect { get; set; }
[Display(Name = "Baseline Volume")]
public float baselineVolume { get; set; }
[Display(Name = "Billing Month")]
public string BillingMonth { get; set; }
[Display(Name = "Monthly Device Count")]
public float DeviceCount { get; set; }
}
**Controller**
//Get Method
public IActionResult Create()
{
DBM2BillingViewModel dbm2billingVM = new DBM2BillingViewModel();
dbm2billingVM.databaseM2List = _context.databaseM2s.ToList();
return View(dbm2billingVM);
}
//Post Method
[HttpPost]
[ValidateAntiForgeryToken]
public IActionResult Create(DBM2BillingViewModel model)
{
foreach(var dbm2 in model.databaseM2List)
{
DeviceBilling addModel = new DeviceBilling();
addModel.Name = dbm2.Name;
addModel.TrackName = "Database M2";
addModel.POItemNo = dbm2.POItemNo;
addModel.DateOfEffect = dbm2.DateOfEffect;
addModel.baselineVolume = dbm2.BaselineVolume;
addModel.BillingMonth = model.BillingMonth;
addModel.DeviceCount = model.DeviceCount;
_context.deviceBillings.Add(addModel);
}
_context.SaveChanges();
return RedirectToAction(nameof(Index));
}
enter code here
View
#model FinancantPro.Models.DeviceCountModel.DBM2BillingViewModel
#{
ViewData["Title"] = "Create";
}
<div class="container">
<table class="table table-striped border">
<thead>
<tr class="table-info">
<th>#Html.DisplayName("Item Name")</th>
<th>#Html.DisplayName("PO Item No#")</th>
<th>#Html.DisplayName("Date Of Effect")</th>
<th>#Html.DisplayName("Baseline Volume")</th>
<th>#Html.DisplayName("Billing Month")</th>
<th>#Html.DisplayName("Device Count")</th>
</tr>
</thead>
<tbody>
#for (int i = 0; i < Model.databaseM2List.Count; i++)
{
<tr>
<td>
#Html.HiddenFor(d => d.databaseM2List[i].Id)
#Html.DisplayFor(d => d.databaseM2List[i].Name)
</td>
<td>
#Html.DisplayFor(d => d.databaseM2List[i].POItemNo)
</td>
<td>
#Html.DisplayFor(d => d.databaseM2List[i].DateOfEffect)
</td>
<td>
#Html.DisplayFor(d => d.databaseM2List[i].BaselineVolume)
</td>
<td>
#Html.TextBoxFor(d => d.BillingMonth, new { #class = "form-control" })
</td>
<td>
#Html.TextBoxFor(d => d.DeviceCount, new { #class = "form-control" })
</td>
</tr>
}
</tbody>
</table>
<div class="form-group">
<input type="submit" class="btn btn-primary" value="Create" />
</div>
</div>
**************************
If I add list in View I am not able to resolve the Model

asp net mvc3 post a list of objects to action

I created a page with aspnet mvc3. It show all users info as a list. I want to do something with this list. There are some checkboxes that belong to each items. When I click some checkboxes and press submit button, I want to post the whole list as a collection and save each items of this collection to database. There are several notes on internet but there is no exact solution. I have a UserDto. and want to use this to transfer users data in all sections.
Does anyone have any full solution about this or can they give any idea?
Thanks in advance.
Kerem
I added some of my codes. You can see the lead sentences what they are about.
this is my index view detail:
#model List<DomainModel.UserApprovalDto>
#{
ViewBag.Title = "Manage Users";
Layout = "~/Views/Shared/_Layout.cshtml";
}
<h2>
Manage Users</h2>
<div>#Html.Partial("_PartialManageUsers", (List<DomainModel.UserApprovalDto>)Model) </div>
this is my partial view detail:
#model List<DomainModel.UserApprovalDto>
#using (Html.BeginForm("ConfirmUsers", "ManageUsers", FormMethod.Post))
{
<table>
<tr>
<th>
Name
</th>
<th>
Is Reported
</th>
</tr>
#for (int i = 0; i < Model.Count(); i++)
{
<tr>
<td>
#Html.DisplayFor(modelItem => Model[i].FirstName)
</td>
<td>
#Html.CheckBox("IsReported", Model[i].IsReported.HasValue ? Model[i].IsReported.Value : false)
#*#Html.CheckBoxFor(modelItem => Model[i].IsReported.Value);*# #* #if (Model[i].IsReported != null)
{
#Html.CheckBoxFor(modelItem => Model[i].IsReported.Value);
}
else
{
#Html.CheckBoxFor(modelItem => Model[i].IsReported.Value);
}*#
</td>
<td>
</td>
</tr>
}
</table>
<div>
<input name="submitUsers" type="submit" value="Save" />
</div>
}
this is my controller submit method
[HttpPost]
public ActionResult ConfirmUsers(List<DomainModel.UserApprovalDto> collection)
{
if (ModelState.IsValid)
{
//TO-DO
}
return RedirectToAction("Index");
}
this last one is my DTO class detail:
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
namespace DomainModel
{
public class UserApprovalDto
{
public long UserId { get; set; }
public Guid CarUserId { get; set; }
public string FirstName { get; set; }
public string LastName { get; set; }
public string PhotoPath { get; set; }
public string PhotoSmallPath { get; set; }
public string PhotoSquarePath { get; set; }
public string PhotoBigPath { get; set; }
public bool IsBlocked { get; set; }
public bool IsDeleted { get; set; }
}
}
when I submit this code my list return null collection to my controller method.
thanks for your comments.
Assuming you are creating a screen which adds/ remove users to a course. So let's create some viewmodels
public class CourseVM
{
public string Name { set;get;}
public int CourseID { set;get;}
public List<UserVM> Users { set;get;}
public CourseVM()
{
Users=new List<UserVM>();
}
}
public class UserVM
{
public string Name { set;get;}
public int UserID{ set;get;}
public bool IsSelected { set;get;}
}
Now in your GET Action, you will fill the values of the ViewModel and sent it to the view.
public ActionResult Add()
{
var vm = new CourseVM();
//The below code is hardcoded for demo. you may replace with DB data.
vm.Users.Add(new UseVM { Name = "Jon" , UserID=1});
vm.Users.Add(new UseVM { Name = "Scott", UserID=2 });
return View(vm);
}
Now Let's create an EditorTemplate. Go to Views/YourControllerName and Crete a Folder called "EditorTemplates" and Create a new View there with the same name as of the Property Name(UserVM.cshtml)
Add this code to your new editor template.
#model ChannelViewModel
<p>
<b>#Model.Name</b> :
#Html.CheckBoxFor(x => x.IsSelected) <br />
#Html.HiddenFor(x=>x.Id)
</p>
Now in your Main View, Call your Editor template using the EditorFor Html Helper method.
#model CourseVM
#using (Html.BeginForm())
{
<div>
#Html.EditorFor(m=>m.Users)
</div>
<input type="submit" value="Submit" />
}
Now when you post the form, Your Model will have the Users Collection where the Selected Checkboxes will be having a True value for the IsSelected Property.
[HttpPost]
public ActionResult Add(CourseVM model)
{
if(ModelState.IsValid)
{
//Check for model.Users collection and Each items
// IsSelected property value.
//Save and Redirect(PRG pattern)
}
return View(model);
}

Resources