How to take value from Select/Option and inserted into href - asp.net

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:

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)

MVC and Entity Framework Select List

I have an MVC app that I am trying to put together that requires some select lists and drop down lists.
So, I have the following models....
public class Task
{
public int ID { get; set; }
public string Title { get; set; }
......
public virtual ICollection<Monitor> Monitors { get; set; }
public virtual ICollection<Resource> Resources { get; set; }
}
public class Monitor
{
public int ID { get; set; }
public string FirstName { get; set; }
public string LastName { get; set; }
public IList<Task> Tasks { get; set; }
}
public class Resource
{
public int ID { get; set; }
public string FirstName { get; set; }
public string LastName { get; set; }
.....
public IList<Task> Tasks { get; set; }
The interesting part is that when I display a list of tasks, among the other properties that display just fine, I need to display a list of 'Monitors' and a list of 'Resources' that are assigned to the task in the Index view shown below.
#model IEnumerable<ResourceManager.Models.Task>
#{
ViewBag.Title = "Index";
}
<h2>Index</h2>
<p>
#Html.ActionLink("Create New", "Create")
</p>
<table>
<tr>
.....
<th>
#Html.DisplayNameFor(model => model.Title)
</th>
.....
<th>
#Html.DisplayNameFor(model => model.Monitors)
</th>
<th>
#Html.DisplayNameFor(model => model.Resources)
</th>
<th></th>
</tr>
#foreach (var item in Model) {
<tr>
.....
<td>
#Html.DisplayFor(modelItem => item.Title)
</td>
.....
<td>
#if (item.Monitors == null || item.Monitors.Count == 0)
{<span>No Monitors Assigned</span>}
else
{ string.Join(", ", item.Monitors.Select(m => string.Format("{0} {1}", m.FirstName, m.LastName))); }
</td>
<td>
#Html.DisplayFor(modelItem => item.Resources)
</td>
<td>
#Html.ActionLink("Edit", "Edit", new { id=item.ID }) |
#Html.ActionLink("Details", "Details", new { id=item.ID }) |
#Html.ActionLink("Delete", "Delete", new { id=item.ID })
</td>
</tr>
}
</table>
And here is the controller....
public ActionResult Index()
{
var tasks = from t in db.Tasks where t.IsActive == true select t;
return View(tasks);
}
I would like for the list of Monitors and the list of Resources to display as a string on the Index, Delete and Details Views i.e. 'Monitor 1, Monitor 2, Monitor 3' and 'Resource 1, Resource 2, Resource 3'.
However on the other views (Create and Edit), I want them to appear as a selectable list.
First Create Select list in your controller,
var monitors = //Your linq query
ViewData["ddlList"] = monitors .Select(x => new SelectListItem {
Text = x.FirstName,
Value = x.Id.ToString()
}).ToList();
And then you can use it in your view as follows,
<%=Html.DropDownList("myList") %>
For the display of Monitors/Resources (and since you want them displayed as a comma-delimited list), you can just use string.Join:
<td>
#string.Join(",", Model.Monitors.Select(m => string.Format("{0} {1}", m.FirstName, m.LastName)))
</td>
To be able to actually use Html.DisplayFor, you'd have to create a custom display template so Razor will actually know how to respond. To do so, in your Views folder, create new folder called "DisplayTemplates", and in that, create a new partial view called "Monitors.cshtml" and "Resources.cshtml", strongly-typed to IEnumerable<Monitor> and IEnumerable<Resource>, respectively. Then inside that file, you'll just add roughly the same code as above:
#model IEnumerable<Monitor>
#string.Join(",", Model.Select(m => string.Format("{0} {1}", m.FirstName, m.LastName)))
Then in your view, you can call:
#Html.DisplayFor(m => m.Monitors, "Monitors")
Unfortunately, in this example, you'd have to feed the template name because the default behavior of DisplayFor for a list, is to render the display template multiple times, once for each member of the list. You could do something like:
# Monitor.cshtml
#model Monitor
#Model.FirstName #Model.LastName,
And then:
#Html.DisplayFor(m => m.Monitors)
But your last item would have a comma at the end.
For editing the lists, all you have to do is pass the select lists to your view. Optimally, you'd do this with a view model, but for simplicity's sake, I'll just use ViewBag here. In your controller action:
ViewBag.MonitorChoices = db.Monitors.Select(m => new SelectListItem
{
Value = m.ID.ToString(),
Text = string.Format("{0} {1}", m.FirstName, m.LastName)
});
Then, in your create/edit view:
#Html.ListBoxFor(m => m.Monitors, ViewBag.MonitorChoices)
Try as follows,
var monitors = //Your linq query
List monitorList = new List();
foreach (var monitor in monitors ){
SelectListItem item = new SelectListItem();
item.Text = monitor.FirstName;
item.Value = monitor.Id.ToString();
monitorList .Add(item);
}
ViewData["ddlList"] = monitorList;

.net MVC passing linq data from controller to view

I am trying to pass data from controller to view. I have searched the web but could not find a solution.
if I do this it works:
Controller:
var yyy = (from a in Connection.Db.Authorities select a) ;
ViewBag.data = yyy;
View:
#foreach(var item in ViewBag.data)
{
#item.Value
}
But the following code does not work:
Controller:
var yyy = (from a in Connection.Db.Authorities select new {Value = a.Value, TypeCode = a.TypeCode, Return = Calculate(a.Return)}) ;
ViewBag.data = yyy;
View:
#foreach(var item in ViewBag.data)
{
#item.Value
}
It gives "item does not contain a definition for Value" for the view file.
Any help would be great.
Thank you.
-edited: updated the second controller linq query. and corrected the first controller linq query.
It's because You already select Value and Value has no such property as Value. You should change in controller:
var yyy = (from a in Connection.Db.Authorities select a.Value); to
var yyy = (from a in Connection.Db.Authorities select a);
OR change the view to
#foreach(var item in ViewBag.data)
{
#item
}
//////////////////////////////////////////////// EDITS ////////////////////////////////////////////////
Than You should not use anonymous object. You should create ViewModelClass. For Example:
public class AuthoritiesViewModel
{
public string Value { get; set; }
public string TypeCode { get; set; }
public string Return { get; set; }
}
And change your controller:
var yyy = (from a in Connection.Db.Authorities select new AuthoritiesViewModel{ Value = a.Value, TypeCode = a.TypeCode, Return = Calculate(a.Return)});
ViewBag.data = yyy;
and in your view you will be able to use:
<table>
<tr>
<th>Value</th>
<th>TypeCode</th>
<th>Return</th>
</tr>
#foreach(AuthoritiesViewModel item in ViewBag.data)
{
<tr>
<td>#item.Value<td>
<td>#item.TypeCode<td>
<td>#item.Return<td>
</tr>
}
</table>
Also, I have a question to You. Why do You use ViewBag to pass data from controller to view? Why don't You use Model to pass these data to view according to MVC pattern?
//////////////////////////////////////////////// MORE EDITS ////////////////////////////////////////////////
To send more than one query result You can create more complex model. For example:
public class AuthoritiesViewModel
{
public string Value { get; set; }
public string TypeCode { get; set; }
public string Return { get; set; }
}
public class AnotherQueryViewModel
{
public string AnotherQueryValue { get; set; }
public string AnotherQueryTypeCode { get; set; }
public string AnotherQueryReturn { get; set; }
}
public class ModelClass
{
IEnumerable<AuthoritiesViewModel> Authorities { get; set; }
IEnumerable<AnotherQueryViewModel> AnotherQueryResults { get; set; }
}
And change the controller:
var yyy = (from a in Connection.Db.Authorities select new AuthoritiesViewModel{ Value = a.Value, TypeCode = a.TypeCode, Return = Calculate(a.Return)});
// do your another select
var zzz = (from smthing select new AnotherQueryViewModel ...)
// create model instance
ModelClass model = new ModelClass()
{
Authorities = yyy.AsEnumerable(),
AnotherQueryResults = zzz..AsEnumerable()
}
// return view with model
return View("view", model);
and in view you can use:
#model ModelClass
#*display first query result*#
<table>
<tr>
<th>Value</th>
<th>TypeCode</th>
<th>Return</th>
</tr>
#foreach(AuthoritiesViewModel item in Model.Authorities)
{
<tr>
<td>#item.Value<td>
<td>#item.TypeCode<td>
<td>#item.Return<td>
</tr>
}
</table>
#*display second query result*#
<table>
<tr>
<th>Another Query Value</th>
<th>Another Query TypeCode</th>
<th>Another Query Return</th>
</tr>
#foreach(AnotherQueryViewModel item in Model.AnotherQueryResults)
{
<tr>
<td>#item.AnotherQueryValue<td>
<td>#item.AnotherQueryTypeCode<td>
<td>#item.AnotherQueryReturn<td>
</tr>
}
</table>
use sth like this
ViewBag.qualification = new SelectList(db.Lookups.Where(x => x.lookup_type == "Qualification"), "lookup_content", "lookup_content");

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