How to Bind ViewModal to Dropdownlist in asp.net mvc - asp.net

Suppose that we have a doctor with its weekday schedule. I want to display this weekday schedule and update it in the view. My WeekDay class looks like this:
public class WeekDay
{
public int Id { get; set; }
public string DayName { get; set; }
public string EightTen { get; set; }
public string TenTwelve { get; set; }
public string TwelveFourteen { get; set; }
public string FourteenSixteen { get; set; }
public int DoctorId { get; set; }
public Doctor Doctor { get; set; }
}
And Here is the ViewModel I've created to pass it to the view:
public class DoctorWeekDaysViewModel
{
public DoctorWeekDaysViewModel()
{
WeekDays = new List<WeekDay>();
}
public DoctorWeekDaysViewModel(IEnumerable<WeekDay> weekDay = null)
{
WeekDays = weekDay ?? new List<WeekDay>();
}
public IEnumerable<WeekDay> WeekDays { get; set; }
}
In the controller, the corresponding action will return 6 objects of WeekDay Class. In this situation, I've converted it into list and created a ViewModel and returned the ViewModel to the view:
public ActionResult EditTimeTable()
{
string username = Session["Username"].ToString();
var doctor = _context.Doctors.FirstOrDefault(a => a.Username.Equals(username));
var weekdays = _context.WeekDays.Include(a => a.Doctor).Where(a => a.DoctorId.Equals(doctor.Id)).ToList();
DoctorWeekDaysViewModel viewModel = new DoctorWeekDaysViewModel(weekdays);
return View(viewModel);
}
Then In the view I've took it and showed it this way:
#model ClinicWebApp.Models.ViewModel.DoctorWeekDaysViewModel
#using (Html.BeginForm(FormMethod.Post))
{
#Html.AntiForgeryToken()
<div class="calendar-main mb-30">
<div class="row">
#{
var listItems = new List<ListItem> {
new ListItem { Text = "استراحت", Value = "استراحت" },
new ListItem { Text = "ویزیت", Value = "ویزیت" },
new ListItem { Text = "نهار", Value = "نهار" },
new ListItem { Text = "صبحانه", Value = "صبحانه" },
new ListItem { Text = "خالی", Value = "خالی" },
};
}
<table class="mb-0 table table-hover table-dark">
<thead>
<tr>
<th scope="col">#</th>
<th scope="col">8 تا 10</th>
<th scope="col">10 تا 12</th>
<th scope="col">12 تا 14</th>
<th scope="col">14 تا 16</th>
</tr>
</thead>
<tbody>
#foreach (var weekday in Model.WeekDays)
{
<tr>
<th scope="row">#weekday.DayName</th>
<td>
#Html.DropDownListFor(model => weekday.EightTen, new SelectList(listItems), weekday.EightTen, new {#class = "custom-select my-1 mr-sm-2"})
</td>
<td>
#Html.DropDownListFor(model => weekday.TenTwelve, new SelectList(listItems), weekday.TenTwelve, new {#class = "custom-select my-1 mr-sm-2"})
</td>
<td>
#Html.DropDownListFor(model => weekday.TwelveFourteen, new SelectList(listItems), weekday.TwelveFourteen, new {#class = "custom-select my-1 mr-sm-2"})
</td>
<td>
#Html.DropDownListFor(model => weekday.FourteenSixteen, new SelectList(listItems), weekday.FourteenSixteen, new {#class = "custom-select my-1 mr-sm-2"})
</td>
</tr>
}
</tbody>
</table>
</div>
</div>
<footer class="bg-white p-4">
<div class="row">
<div class="col-md-12">
<div class="pull-left">
<button type="submit" class="btn btn-primary">save</button>
</div>
</div>
</div>
</footer>
}
The Output of This View is fine and everything is shown correctly:
Actual Html Output
But when I change the dropdownlist values and submit it to the corresponding action, The ViewModel will be null. here is my ActionResult:
[HttpPost]
[ValidateAntiForgeryToken]
public ActionResult EditTimeTable(DoctorWeekDaysViewModel viewModel)
{
...
}
I think the problem is my viewModel or dropdownlist that configured incorrectly. please help me to solve this problem.

You should custome Name of dropdown to make it correctly.
#Html.DropDownListFor(model => weekday.EightTen, new SelectList(listItems), weekday.EightTen, new {#class = "custom-select my-1 mr-sm-2", Name = "WeekDays[0].EightTen"})
Note: Name = WeekDays[0].EightTen
0: Index, increase for each loop.
EightTen: Name of each property follow up your dropdown accordingly.

Instead of using foreach, use for loop to iterate the weekday list.
#for (var weekday=0; weekday < Model.WeekDays.Count; weekday++)
{
<tr>
<th scope="row">#weekday.DayName</th>
<td>
#Html.DropDownListFor(m => m.WeekDays.ElementAt(weekday).EightTen, new SelectList(listItems), Model.WeekDays.ElementAt(weekday).EightTen, new {#class = "custom-select my-1 mr-sm-2"})
</td>
<td>
#Html.DropDownListFor(m => m.WeekDays.ElementAt(weekday).TenTwelve, new SelectList(listItems), Model.WeekDays.ElementAt(weekday).TenTwelve, new {#class = "custom-select my-1 mr-sm-2"})
</td>
<td>
#Html.DropDownListFor(m => m.WeekDays.ElementAt(weekday).TwelveFourteen, new SelectList(listItems), Model.WeekDays.ElementAt(weekday).TwelveFourteen, new {#class = "custom-select my-1 mr-sm-2"})
</td>
<td>
#Html.DropDownListFor(m => m.WeekDays.ElementAt(weekday).FourteenSixteen, new SelectList(listItems), Model.WeekDays.ElementAt(weekday).FourteenSixteen, new {#class = "custom-select my-1 mr-sm-2"})
</td>
</tr>
}

Related

Dropdown Data Binding Problem in ASP.NET Core 6 MVC

I am using SelectListItem in the controller for binding my dropdown data. All the dropdown options are showing perfectly in the dropdown list, but when I try to save, the problem occurs. It's not adding the dropdown options data rather than its adding dropdown data's id.
All the related models, controller and views are shown here:
BuyerSelectList model class:
public class BuyerSelectList
{
[Key]
public int Id { get; set; }
[DisplayName("BUYER")]
public string Buyer { get; set; }
}
ItemSelectList model class:
public class ItemSelectList
{
[Key]
public int Id { get; set; }
[DisplayName("ITEM")]
public string Item { get; set; }
}
BTBNewLien2 model class:
public class BTBNewLien2
{
public int Id { get; set; }
[Required]
[DisplayName("Buyer")]
public int BuyerSelectListId { get; set; }
[ForeignKey("BuyerSelectListId")]
[ValidateNever]
public BuyerSelectList BuyerSelectList { get; set; }
[Required]
[DisplayName("Item")]
public int ItemSelectListId { get; set; }
[ForeignKey("ItemSelectListId")]
[ValidateNever]
public ItemSelectList ItemSelectList { get; set; }
}
BTBNewLien2 controller (here I added all the data binding functionalities for my dropdown):
namespace CommercialCalculatorWeb.Areas.Admin.Controllers
{
public class BTBNewLien2Controller : Controller
{
private readonly IUnitOfWork _unitOfWork;
public BTBNewLien2Controller(IUnitOfWork unitOfWork)
{
_unitOfWork = unitOfWork;
}
public IActionResult Index()
{
IEnumerable<BTBNewLien2> objBTBNewLienList = _unitOfWork.BTBNewLien2.GetAll();
return View(objBTBNewLienList);
}
public IActionResult Create()
{
BTBNewLien2 btbNewLien2 = new();
IEnumerable<SelectListItem> BuyerSelectList = _unitOfWork.Buyer.GetAll().Select(
c => new SelectListItem
{
Text = c.Buyer,
Value = c.Id.ToString()
});
IEnumerable<SelectListItem> ItemSelectList = _unitOfWork.Item.GetAll().Select(
c => new SelectListItem
{
Text = c.Item,
Value = c.Id.ToString()
});
ViewBag.BuyerSelectList = BuyerSelectList;
ViewBag.ItemSelectList = ItemSelectList;
return View(btbNewLien2);
}
[HttpPost]
[ValidateAntiForgeryToken]
public IActionResult Create(BTBNewLien2 obj)
{
if (ModelState.IsValid)
{
_unitOfWork.BTBNewLien2.Add(obj);
_unitOfWork.Save();
TempData["success"] = "Row Created Successfully!";
return RedirectToAction("Index");
}
return View(obj);
}
}
}
BTBNewLien2 create view:
#model CommercialCalculator.Models.BTBNewLien2
#{
ViewData["Title"] = "Create";
}
<h1>Create</h1>
<h4>BTBNewLien2</h4>
<hr />
<div class="row ml-6">
<div class="col-md-4">
<form asp-action="Create">
<div class="form-group">
<label asp-for="BuyerSelectListId" class="control-label">Buyer</label>
<select asp-for="BuyerSelectListId" asp-items="ViewBag.BuyerSelectList" class="form-control">
<option disabled selected>--Select Buyer--</option>
</select>
</div>
<div class="form-group">
<label asp-for="ItemSelectListId" class="control-label">Item</label>
<select asp-for="ItemSelectListId" asp-items="ViewBag.ItemSelectList" class="form-control">
<option disabled selected>--Select Item--</option>
</select>
</div>
<div class="form-group">
<input type="submit" value="Create" class="btn btn-primary" />
</div>
</form>
</div>
</div>
BTBNewLien2 index view:
#model IEnumerable<CommercialCalculator.Models.BTBNewLien2>
#{
ViewData["Title"] = "Index";
}
<table class="table table-bordered table-hover table-sm align-middle m-0" id="header">
<tr class="m-0" style="text-align:center;background-color: #17A2B8">
<th width="20%">
#Html.DisplayNameFor(model => model.BuyerSelectList)
</th>
<th>
#Html.DisplayNameFor(model => model.ItemSelectList)
</th>
</tr>
#foreach (var BTBNewLien2 in Model)
{
<tr class="m-0">
<td>
#Html.DisplayFor(modelItem => BTBNewLien2.BuyerSelectList)
</td>
<td>
#Html.DisplayFor(modelItem => BTBNewLien2.ItemSelectList)
</td>
</tr>
}
</table>
Try this way:
#Html.DropDownList("ItemSelectListId", new SelectList(ViewBag.ItemSelectListId, "Text", "Text"), "-- Select Item --", new { required = true, #class = "form-control" })
In my code, it works fine:
Controller:
[HttpGet]
public IActionResult Create()
{
List<SelectListItem> test = new()
{
new SelectListItem { Value = "1", Text = "test1" },
new SelectListItem { Value = "2", Text = "test2" },
new SelectListItem { Value = "3", Text = "test3" },
new SelectListItem { Value = "4", Text = "test4" }
};
ViewBag.ItemSelectListId = test;
return View();
}
[HttpPost]
public IActionResult Create(Test test)
{
return View();
}
View:
<div class="row ml-6">
<div class="col-md-4">
<form asp-action="Create">
<div class="form-group">
<label asp-for="ItemSelectListId" class="control-label">Buyer</label>
#Html.DropDownList("ItemSelectListId", new SelectList(ViewBag.ItemSelectListId, "Text", "Text"), "-- Select Item --", new { required = true, #class = "form-control" })
</div>
<div class="form-group">
<input type="submit" value="Create" class="btn btn-primary" />
</div>
</form>
</div>
</div>
Test Result:

How to display combobox in a table?RSS

How to display a combobox for the current model in the table?
How to make the model correctly in order to display a combobox in the table?
Currently, I get the result, which is shown in the picture.
ASP.NET Core 3.1
Problems:
  - in the field with the combo box the current value of the field for recording is not displayed.
Company.cs
public class Company
{
public int Id { get; set; }
public string Picture { get; set; }
public string Name { get; set; }
public string Description{ get; set; }
public bool Status { get; set; }
public Status2 Status2Value { get; set; }
public class Status2
{
public int ID { get; set; }
public string Status { get; set; }
}
}
HomeController.cs
public class HomeController : Controller
{
public IActionResult Index()
{
List<Company> companies_List = new List<Company>();
companies_List = MockCompanyData.CompanyList_prop;
List<Company.Status2> status2_List = new List<Company.Status2>();
status2_List = MockCompanyData.CompanyStatus2_prop;
IndexVM indexVM = new IndexVM { Companies = companies_List, companyStatus2 = status2_List };
return View(indexVM);
}
}
IndexVM.cs
public class IndexVM
{
public IEnumerable<Company> Companies { get; set; }
public IEnumerable<Company.Status2> companyStatus2 { get; set; }
}
MockCompanyData.cs
static class MockCompanyData
{
static string mainPathForImg = #"";
static List<Company.Status2> companyStatus2List = new List<Company.Status2>
{
new Company.Status2 {ID=1, Status = ""},
new Company.Status2 {ID=2, Status = "Yes"},
new Company.Status2 {ID=3, Status = "No"}
};
static List<Company> companyList = new List<Company>
{
new Company {Id = 1, Picture = mainPathForImg + #"~/img/number_1_blue.png", Name ="Name_Company_1", Description ="Description_1", Status = true, Status2Value = companyStatus2List[0]},
new Company {Id = 2, Picture = mainPathForImg + #"~/img/number_2_blue.png", Name ="Name_Company_2", Description ="Description_2", Status = false, Status2Value = companyStatus2List[1]},
new Company {Id = 3, Picture = mainPathForImg + #"~/img/number_3_blue.png", Name ="Name_Company_3", Description ="Description_3", Status = true, Status2Value =companyStatus2List[0]}
};
public static List<Company> CompanyList_prop
{
get
{
return companyList;
}
set
{
companyList = value;
}
}
public static List<Company.Status2> CompanyStatus2_prop
{
get
{
return companyStatus2List;
}
set
{
companyStatus2List = value;
}
}
}
Index.cshtml
#using WebApplCore.Core.ViewModels;
#using WebApplCore.Models;
#model IndexVM;
#addTagHelper *, Microsoft.AspNetCore.Mvc.TagHelpers
<head>
<link href="~/css/bootstrap.min.css" rel="stylesheet" type="text/css" />
</head>
<body>
<div class="container">
<table class="table table-sm table-hover table-striped">
<thead class="thead-dark">
#{var headerMetadata = Model.Companies.FirstOrDefault();}
<tr>
<th>
#Html.DisplayNameFor(model => headerMetadata.Id)
</th>
<th>
#Html.DisplayNameFor(model => headerMetadata.Picture)
</th>
<th>
#Html.DisplayNameFor(model => headerMetadata.Name)
</th>
<th>
#Html.DisplayNameFor(model => headerMetadata.Description)
</th>
<th>
#Html.DisplayNameFor(model => headerMetadata.Status)
</th>
<th>
#Html.DisplayNameFor(model => headerMetadata.Status2Value)
</th>
<th></th>
</tr>
</thead>
<tbody>
#foreach (Company item in Model.Companies)
{
<tr>
<td>
#Html.DisplayFor(modelItem => item.Id)
#*#item.Id*#
</td>
<td>
<img src=#Html.DisplayFor(modelItem => item.Picture) class="rounded-circle" asp-append-version="true" alt="No Picture">
</td>
<td>
#Html.DisplayFor(modelItem => item.Name)
</td>
<td>
#Html.DisplayFor(modelItem => item.Description)
</td>
<td>
<input type="checkbox" value=#Html.DisplayFor(modelItem => item.Status)>
</td>
<td>
<select name="companyId" class="form-control">
#foreach (Company.Status2 status2 in Model.companyStatus2)
{
<option value="#status2.ID">#Html.DisplayFor(modelItem => status2.Status)</option>
}
</select>
</td>
<td>
<a asp-action="Edit" asp-route-id="#item.Id">Edit</a> |
<a asp-action="Details" asp-route-id="#item.Id">Details</a> |
<a asp-action="Delete" asp-route-id="#item.Id">Delete</a>
</td>
</tr>
}
</tbody>
</table>
</div>
</body>
Picture-1
Picture-2
As I understand, You want to set dropdown value: here is changes in you code:
Model:
public class Company
{
public int Id { get; set; }
public string Picture { get; set; }
public string Name { get; set; }
public string Description { get; set; }
public bool Status { get; set; }
public int SelectedStatus2Value { get; set; }
public class Status2
{
public int ID { get; set; }
public string Status { get; set; }
}
}
static class MockCompanyData
{
static string mainPathForImg = #"";
static List<Company.Status2> companyStatus2List = new List<Company.Status2>
{
new Company.Status2 {ID=1, Status = ""},
new Company.Status2 {ID=2, Status = "Yes"},
new Company.Status2 {ID=3, Status = "No"}
};
static List<Company> companyList = new List<Company>
{
new Company {Id = 1, Picture = mainPathForImg + #"~/img/number_1_blue.png", Name ="Name_Company_1", Description ="Description_1", Status = true, SelectedStatus2Value = companyStatus2List[1].ID},
new Company {Id = 2, Picture = mainPathForImg + #"~/img/number_2_blue.png", Name ="Name_Company_2", Description ="Description_2", Status = false, SelectedStatus2Value = companyStatus2List[2].ID},
new Company {Id = 3, Picture = mainPathForImg + #"~/img/number_3_blue.png", Name ="Name_Company_3", Description ="Description_3", Status = true, SelectedStatus2Value =companyStatus2List[2].ID}
};
public static List<Company> CompanyList_prop
{
get
{
return companyList;
}
set
{
companyList = value;
}
}
public static List<Company.Status2> CompanyStatus2_prop
{
get
{
return companyStatus2List;
}
set
{
companyStatus2List = value;
}
}
View :
#using WebApplCore.Core.ViewModels;
#using WebApplCore.Models;
#model IndexVM;
#addTagHelper *, Microsoft.AspNetCore.Mvc.TagHelpers
<head>
<link href="~/css/bootstrap.min.css" rel="stylesheet" type="text/css" />
</head>
<body>
<div class="container">
<table class="table table-sm table-hover table-striped">
<thead class="thead-dark">
#{var headerMetadata = Model.Companies.FirstOrDefault();}
<tr>
<th>
#Html.DisplayNameFor(model => headerMetadata.Id)
</th>
<th>
#Html.DisplayNameFor(model => headerMetadata.Picture)
</th>
<th>
#Html.DisplayNameFor(model => headerMetadata.Name)
</th>
<th>
#Html.DisplayNameFor(model => headerMetadata.Description)
</th>
<th>
#Html.DisplayNameFor(model => headerMetadata.Status)
</th>
<th>
Status2Value
</th>
<th></th>
</tr>
</thead>
<tbody>
#foreach (Company item in Model.Companies)
{
<tr>
<td>
#Html.DisplayFor(modelItem => item.Id)
#*#item.Id*#
</td>
<td>
<img src=#Html.DisplayFor(modelItem => item.Picture) class="rounded-circle" asp-append-version="true" alt="No Picture">
</td>
<td>
#Html.DisplayFor(modelItem => item.Name)
</td>
<td>
#Html.DisplayFor(modelItem => item.Description)
</td>
<td>
<input type="checkbox" value=#Html.DisplayFor(modelItem => item.Status)>
</td>
<td>
<select name="companyId" class="form-control">
#foreach (Company.Status2 status2 in Model.companyStatus2)
{
if (status2.ID != item.SelectedStatus2Value)
{
<option value="#status2.ID">#Html.DisplayFor(modelItem => status2.Status)</option>
}
if (status2.ID == item.SelectedStatus2Value)
{
<option selected value="#status2.ID">#Html.DisplayFor(modelItem => status2.Status)</option>
}
}
</select>
</td>
<td>
<a asp-action="Edit" asp-route-id="#item.Id">Edit</a> |
<a asp-action="Details" asp-route-id="#item.Id">Details</a> |
<a asp-action="Delete" asp-route-id="#item.Id">Delete</a>
</td>
</tr>
}
</tbody>
</table>
</div>
</body>
Output Here:

MVC4 - Partial View List Model binding during Submit to Main view

I have view model which has a list of child models to render the partial view (below).
public class PRDocument
{
[Key]
[Column(Order = 0)]
public int Id { get; set; }
[DisplayName("Vendor Name")]
[Column(Order = 2)]
public int VendorId { get; set; }
public virtual ICollection<PRDocumentQuotation> PRDocumentQuotations { get; set; }
[NotMapped]
public List<PRDocumentQuotation> Quotations { get; set; }
public PRDocument()
{
Quotations = new List<PRDocumentQuotation>();
}
}
public class PRDocumentQuotation
{
[Key]
[Column(Order = 0)]
public int Id { get; set; }
[Required]
[Column(Order = 1)]
public int PRDocumentId { get; set; }
[Display(Name = "Uploaded File")]
[Column(Order = 2)]
public string FileName { get; set; }
}
And in the Partial View rendered like this.
#Html.Partial("_PRDocs", Model.Quotations)
Here is my partial view.
#model IEnumerable<JKLLPOApprovalApp.Models.PRDocumentQuotation>
<table class="table">
<tr>
<th>
#Html.DisplayNameFor(model => model.FileName)
</th>
<th></th>
</tr>
#foreach (var item in Model) {
<tr>
#Html.HiddenFor(modelItem => item.PRDocumentId)
<td>
#Html.DisplayFor(modelItem => item.FileName)
</td>
<td>
#Html.ActionLink("Delete", "Delete", new { id=item.Id })
</td>
</tr>
}
</table>
And the controller actions
[HttpPost]
[ValidateAntiForgeryToken]
public ActionResult Create(PRDocument pRDocument)
{
if (ModelState.IsValid)
{
pRDocument.PRDocumentQuotations = pRDocument.Quotations;
db.tbl_PRDocuments.Add(pRDocument);
db.SaveChanges();
return RedirectToAction("Index");
}
return View(pRDocument);
}
View Data Main View
#model JKLLPOApprovalApp.Models.PRDocument
#{
ViewBag.Title = "Create";
Layout = "~/Views/Shared/_Layout.cshtml";
}
<h2>Create</h2>
#using (Html.BeginForm())
{
#Html.AntiForgeryToken()
<div class="form-horizontal">
<h4>PRDocument</h4>
<hr />
#Html.ValidationSummary(true, "", new { #class = "text-danger" })
<div class="form-group">
#Html.LabelFor(model => model.VendorId, htmlAttributes: new { #class = "control-label col-md-2" })
<div class="col-md-10">
#Html.EditorFor(model => model.VendorId, new { htmlAttributes = new { #class = "form-control" } })
#Html.ValidationMessageFor(model => model.VendorId, "", new { #class = "text-danger" })
</div>
</div>
#Html.Partial("_PRDocs", Model.Quotations)
<div class="form-group">
<div class="col-md-offset-2 col-md-10">
<input type="submit" value="Create" class="btn btn-default" />
</div>
</div>
</div>
}
<div>
#Html.ActionLink("Back to List", "Index")
</div>
What i want is to get the partial view data list (PRDocumentQuotation) into the Create action, bound with main model (PRDocument). How can i do this?
Interesting Question :)
The issue was that Model binding to list should have unique names. So the Generated HTML Should look like below:
<input id="Quotations_0__PRDocumentId" name="Quotations[0].PRDocumentId" type="hidden" value="0">
<input id="Quotations_1__PRDocumentId" name="Quotations[1].PRDocumentId" type="hidden" value="0">
The recommended solution is to use Editor Templates, Check this and this.
But I am giving alternate solution below using for loop to create unique names with index, taken from this post which faced same issue.
In Main View:
Pass The Main Model Instead
#Html.Partial("_PRDocs", Model)
Partial View:
#model JKLLPOApprovalApp.Models.PRDocument
<table class="table">
#if (Model.Quotations != null)
{
for (var i = 0; i < Model.Quotations.Count(); i++)
{
<tr>
<th>
#Html.DisplayNameFor(model => Model.Quotations[i].FileName)
</th>
<th></th>
</tr>
<tr>
#Html.HiddenFor(modelItem => Model.Quotations[i].PRDocumentId)
<td>
#Html.DisplayFor(modelItem => Model.Quotations[i].FileName)
</td>
<td>
#Html.ActionLink("Delete", "Delete", new { id = Model.Quotations[i].Id })
</td>
</tr>
}
}
</table>
Hope helps.

ASP.NET MVC empty KeyValuePair into Controller

I have an Model like KeyValuePair<Book, List<Author>>, after saving changes to controller comes empty model. To Edit(int id) comes Id of Book.
To this method need to get KeyValuePair filled, but it comes empty. Help please.
[HttpPost]
public ActionResult Edit(KeyValuePair<Book, List<Author>> data)
Controller
public class HomeController : Controller
{
static ViewModelAuthorsBooks data = new ViewModelAuthorsBooks();
static Dictionary<Book, List<Author>> tempDict = new Dictionary<Book, List<Author>>();
public ActionResult Index()
{
data = new ViewModelAuthorsBooks();
data.dictionary = new Dictionary<Book, List<Author>>();
List<Author> temp = new List<Author>();
Book book1 = new Book
{
Id = 0,
Name = "Book1",
Genre = "Genre1",
Description = "DescriptionDescription",
Price = 22.42M
};
Author author = new Author
{
Id = 0,
Name = "Name1",
Surname = "Surname1",
SecondName = "Secondname1"
};
temp.Add(author);
Author author2 = new Author
{
Id = 1,
Name = "Name2",
Surname = "Surname2",
SecondName = "Secondname2"
};
temp.Add(author2);
data.dictionary.Add(book1, temp);
temp = new List<Author>();
Book book2 = new Book
{
Id = 1,
Name = "Book2",
Genre = "Genre2",
Description = "DescriptionDescription2",
Price = 44.44M
};
Author author3 = new Author
{
Id = 2,
Name = "Name3",
Surname = "Surname3",
SecondName = "Secondname3"
};
temp.Add(author3);
data.dictionary.Add(book2, temp);
tempDict = data.dictionary;
return View(data.dictionary);
}
public ActionResult Edit(int id)
{
var model = tempDict.FirstOrDefault(x => x.Key.Id == id);
return View(model);
}
[HttpPost]
public ActionResult Edit(KeyValuePair<Book, List<Author>> data)
{
if (ModelState.IsValid)
{
return RedirectToAction("Index");
}
else
{
return View(data);
}
}
}
Classes
public class Book
{
public int Id { get; set; }
public string Name { get; set; }
public decimal Price { get; set; }
public string Description { get; set; }
public string Genre { get; set; }
}
public class Author
{
public int Id { get; set; }
public string Name { get; set; }
public string Surname { get; set; }
public string SecondName { get; set; }
}
public class ViewModelAuthorsBooks
{
public Dictionary<Book,List<Author>> dictionary { get; set; }
}
Views/Index
#using KeyValuePairTest.Models
#model IEnumerable<KeyValuePair<Book,List<Author>>>
#{
ViewBag.Title = "Index";
}
<h2>Index</h2>
<div class="panel panel-default">
<div class="panel-heading">
Books List
</div>
<div class="panel-body">
<table class="table table-striped table-condensed table-bordered">
<tr>
<th class="text-center">
#Html.DisplayNameFor(x => x.Key.Id)
</th>
<th class="text-center">
#Html.DisplayNameFor(x => x.Key.Name)
</th>
<th class="text-center">
#Html.DisplayNameFor(x => x.Key.Genre)
</th>
<th class="text-right">
#Html.DisplayNameFor(x => x.Key.Price)
</th>
<th class="text-center">
Action
</th>
</tr>
#foreach (var item in Model)
{
<tr>
<td class="text-right">
#item.Key.Id
</td>
<td>
#Html.ActionLink(item.Key.Name, "Edit", new { item.Key.Id })
</td>
<td>
#Html.DisplayFor(modelItem => item.Key.Genre)
</td>
<td class="text-right">
#item.Key.Price.ToString("# USD")
</td>
<td class="text-center">
#using (Html.BeginForm("Delete", "Admin"))
{
#Html.Hidden("id", item.Key.Id)
<input type="submit" class="btn btn-default btn-xs" value="Remove" />
}
</td>
</tr>
}
</table>
</div>
<div class="panel-footer">
#Html.ActionLink("Add", "Create", null, new { #class = "btn btn-default" })
</div>
</div>
Views/Edit
#using KeyValuePairTest.Models
#model KeyValuePair<Book, List<Author>>
#{
ViewBag.Title = "Edit";
}
<div class="panel">
<div class="panel-heading">
<h5>Edit Book: #Model.Key.Name</h5>
</div>
#using (Html.BeginForm("Edit", "Home", FormMethod.Post, new { app = #Model }))
{
<div class="panel-body">
#Html.HiddenFor(b => b.Key.Id)
<div class="form-group">
<label>Name:</label>
#Html.TextBoxFor(x => x.Key.Name, new { #class = "form-control" })
<input type="text" name="m" />
<label>Genre:</label>
#Html.TextBoxFor(x => x.Key.Genre, new { #class = "form-control" })
<label>Authors:</label>
#foreach (var author in Model.Value)
{
<label>Name</label>
#Html.TextBoxFor(x => author.Name);
<label>Surname</label>
#Html.TextBoxFor(x => author.Surname);
<label>Second name</label>
#Html.TextBoxFor(x => author.SecondName);
<p></p>
}
<label>Description:</label>
#Html.TextAreaFor(x => x.Key.Description, new { #class = "form-control", rows = 5 })
<label>Price:</label>
#Html.TextBoxFor(x => x.Key.Price, new { #class = "form-control" })
</div>
</div>
<div class="panel-footer">
<input type="submit" value="Save" class="btn btn-primary" />
#Html.ActionLink("Cancel", "Index", null, new { #class = "btn btn-default" })
</div>
}
</div>
Dictionary contains keys and values
In edit we see, that dictionary has values, they shown
Change value of Book name
Null
Thank's all for help, I find a solution
public class ViewModelUpdated
{
public Book book { set; get; }
public List<Author> lstAuthors { set; get; }
}
Just don't do a dictionary that's all :3

Radio button list using editor templates for merging contacts

I am trying to display a form for merging two contacts in ASP.net MVC 5.
The form should look like this where each row holds a radio button group consisting of 2 options:
The form shows up just fine, and the radio groups work (I can select each group). However, when the model is posted back to the server, the Values list is empty (not preserved). I would like to get both the selected id but of course also the actual text value back in the controller. I prefer to do this using Editor Templates and if possible without for loops.
The current results (Values = null):
EDIT to respond to comments: I would prefer not to re-fetch the values in the controller again, because it results in a call to a web service. I have tried some variants of HiddenFor without results.
My models look like this:
public class Contact
{
public List<ContactRow> Rows { get; set; }
public Contact()
{
this.Rows = new List<ContactRow>();
this.Rows.Add(new ContactRow("First Name", "Homer", "Homie"));
this.Rows.Add(new ContactRow("Last Name", "Simpson", "Simson"));
this.Rows.Add(new ContactRow("Email", "mail1", "mail2"));
this.Rows.Add(new ContactRow("Company Phone", "Phone1", "Phone2"));
this.Rows.Add(new ContactRow("Mobile Phone", "Mobile1", "Mobile2"));
}
}
public class ContactRow
{
public int Selection { get; set; }
public string Label { get; set; }
public List<ValueSet> Values { get; set; }
public ContactRow(string Label, string LeftValue, string RightValue, int Selection = 0)
{
if (LeftValue== null) LeftValue= "";
if (RightValue== null) RightValue= "";
this.Label = Label;
this.Selection = Selection;
this.Values = new List<ValueSet>(2);
this.Values.Add(new ValueSet() { ID = 0, ValueText = LeftValue});
this.Values.Add(new ValueSet() { ID = 1, ValueText = RightValue});
}
public ContactRow() { }
}
public class ValueSet
{
public int ID { set; get; }
public string ValueText { set; get; }
}
The Controller:
public ActionResult Index()
{
Contact model = new Contact();
return View(model);
}
public ActionResult MergeContacts(Contact model)
{
return RedirectToAction("Index");
}
And the views:
Index.cshtml
#model RadioTest.Models.Contact
#{
ViewBag.Title = "Home Page";
}
#using (Html.BeginForm("MergeContacts", "Home", FormMethod.Post, new { encType = "multipart/form-data", id = "contactDetailsForm", name = "contactDetailsForm" }))
{
<div>
<table class="table" width="100%">
<tr>
<th style="text-align:left">Label</th>
#*<th style="text-align:right">R1</th>*#
<th style="text-align:left">
Left Value
</th>
#*<th style="text-align:right">R2</th>*#
<th style="text-align:left">
Right Value
</th>
</tr>
#Html.EditorFor(model => model.Rows)
</table>
<input type="submit" />
</div>
}
Editor Template for ContactRow:
ContactRow.cshtml
#model RadioTest.Models.ContactRow
<tr>
<td style="text-align:left">
#Html.DisplayFor(model => model.Label)
</td>
#foreach (var v in Model.Values)
{
<td style="text-align:left">
#Html.RadioButtonFor(model => model.Selection, v.ID) #v.ValueText
</td>
}
</tr>
#Html.HiddenFor(model => model.Label)
Just change your foreach to for:
#model MVCApp.Controllers.ContactRow
<tr>
<td style="text-align:left">
#Html.DisplayFor(model => model.Label)
</td>
#for (int i = 0; i < Model.Values.Count; i++)
{
<td style="text-align:left">
#Html.RadioButtonFor(model => model.Selection, Model.Values[i].ID) #Model.Values[i].ValueText
#Html.HiddenFor(model => Model.Values[i].ID)
#Html.HiddenFor(model => Model.Values[i].ValueText)
</td>
}
</tr>
#Html.HiddenFor(model => model.Label)

Resources