Get multiple checked checkbox values in MVC controller - asp.net-mvc-4

My code is below:
On page i have a products list with checkbox, code & name of that product.
When selecting multiple checkboxes, on submit click, i need to get the selected checkbox values & save it in the DB.
Product View Model class:
public class ProductVM
{
public ProductVM()
{
this.ProductsList = new List<Product>();
}
public List<Product> ProductsList { get; set; }
public class Product
{
public bool IsSelected { get; set; }
public string Code { get; set; }
public string Name { get; set; }
}
}
Product Controller:
[HttpGet]
public ActionResult Edit()
{
var model = new ProductVM();
var product1 = new ProductVM.Product
{
Code = "Product1",
Name = "Apple"
};
var product2 = new ProductVM.Product
{
Code = "Product2",
Name = "Banana"
};
model.ProductsList.Add(Product1);
model.ProductsList.Add(Product2);
return View(model);
}
[HttpPost]
public ActionResult Edit(ProductVM model)
{
if (model.ProductsList.Any(m => m.Selected))
{
//How to get the selected Code & Name here
}
}
Product View:
#model ProductVM
#using(Html.BeginForm())
{
foreach (var item in Model.ProductsList)
{
#Html.CheckBox("IsSelected", item.IsSelected)
#Html.Label(item.Code)
#Html.Label(item.Name)
}
<input type="submit" />
}

First, you need to use for instead of foreach. Otherwise Razor won't generate the proper field names. Second, you need hidden inputs for the Code and Name properties so these will get posted back:
for (var i = 0; i < Model.ProductsList.Count(); i++)
{
#Html.HiddenFor(m => m.ProductsList[i].Code)
#Html.HiddenFor(m => m.ProductsList[i].Name)
<label>
#Html.CheckBoxFor(m => m.ProductsList[i].IsSelected)
#Html.DisplayFor(m => m.ProductsList[i].Code)
#Html.DisplayFor(m => m.ProductsList[i].Name)
</label>
}

To demo my code from my comment to question- You can get idea from it
#foreach (var item in ViewBag.FocusesList)
{
<label>
<input type="checkbox" value="#item.ConfigurationId" name="FocusList" id="FocusList" /> #item.Value.Name
</label>
}
After submit you have all checked values split by comma in Request["FocusList"]

Related

why checkbox wont check on page load?

i have the following database table for the Compounds table (chemical compounds/elements in the periodic table) there are typos in table data so ignore them
the data is :
the controller :
public class CheckboxController : Controller
{
//
// GET: /Checkbox/
testdbEntities db = new testdbEntities();
[HttpGet]
public ActionResult Index()
{
var comps = db.Compounds.Select(c => new CompoundModel { Id=c.Id, CompoundName=c.Name, IsSelected=c.IsSelected}).ToList();
CheckboxVM cvm = new CheckboxVM { checkboxData=comps};
return View(cvm);
}
[HttpPost]
public string Index(IEnumerable<CheckboxVM> collection)
{
return "";
}
}
Model class CompoundModel is:
public class CompoundModel
{
public int Id { get; set; }
public string Code { get; set; }
public string CompoundName { get; set; }
public bool IsSelected { get; set; }
}
and the ViewModel CheckBoxVM:
public class CheckboxVM
{
public string Id { get; set; }
public string CompoundNmae { get; set; }
public bool IsSelected { get; set; }
public IEnumerable<CompoundModel> checkboxData { get; set; }
}
When the page loads it should display check boxes with names and if db table has checked on them (IsSelected=1) then they should be checked.In the post back i need to receive the id, of the user checked checkboxes. At the moment my code does meet the first requirement to check the checked checkboxes based on IsSelected on page load. Is there a way to fix this?
If you need a video with debugging please ask i will be happy to post : )
THE VIEW: (UPDATE)
#model recitejs1.Models.CheckboxVM
#{
ViewBag.Title = "Index";
}
<h2>Index</h2>
#using (Html.BeginForm())
{
foreach (var item in Model.checkboxData)
{
#Html.CheckBoxFor(x=>x.IsSelected, (item.IsSelected)?new{#checked="check"}:null)#item.CompoundName
#Html.HiddenFor(x=>x.Id, item.Id)
#Html.HiddenFor(x=>x.CompoundNmae, item.CompoundName)
}
<br><br>
<input type="submit" name="name" value="Send" />
}
You cannot use a foreach loop to generate form controls. It generates duplicate name attributes (that have no relationship to your model) and duplicate id attributes (invalid html).
Create a custom `EditorTemplate for your model
In /Views/Shared/EditorTemplates/CompoundModel.cshtml
#model recitejs1.Models.CompoundModel
#Html.HiddenFor(m => m.Id)
#Html.HiddenFor(m => m.CompoundName)
#Html.CheckBoxFor(m => m.IsSelected)
#Html.LabelFor(m => m.CompoundName)
Then in the main view
#model recitejs1.Models.CheckboxVM
....
#using (Html.BeginForm())
{
#Html.EditorFor(m => m.checkboxData)
<input type="submit" name="name" value="Send" />
}
The EditorFor() method will generate the correct html for each item in your collection
Note: You should inspect the html before and after you make this change to better understand how model binding works.
Note also that your POST method parameter needs to be
public string Index(CheckboxVM model)
since that's what the view is based on. However the only property of CheckboxVM that you use in the view is IEnumerable<CompoundModel> checkboxData in which case your view should be
#model IEnumerable<CompoundModel>
...
#Html.EditorFor(m => m)
and keep the POST method as it is (but change the GET method)

Mvc: Getting the selected value of the dropdownlistFor box

In my domain I have this service
public class StudentService
{
private readonly IStudentRepository _studentRepository;
public StudentService(IStudentRepository studentRepository)
{
_studentRepository = studentRepository;
}
public StudentDto DisplayStudentInformation()
{
var objStuSec = _studentRepository.DisplayStudentSection();
return objStuSec;
}
}
Here is my studentDto
public class StudentDto
{
public string StudentId { get; set; }
public string FirstName { get; set; }
public string LastName { get; set; }
public string EmailAddress { get; set; }
public List<DepartmentDto> GetAllDepartments;
}
Here is my code for the Home controller
public class HomeController : Controller
{
private StudentService _objStudentService;
public HomeController(StudentService objStudentService)
{
_objStudentService = objStudentService;
}
public ActionResult Index()
{
ViewBag.Message = "This is a Test";
var displayform = _objStudentService.DisplayStudentInformation();
return View(displayform);
}
}
Here is my html for the form
#using System.Net.Mime
#model Zakota.University.Domain.DTO.StudentDto
<form action="" method="post">
<div>
<label>First Name</label>
#Html.TextBoxFor(x=>x.FirstName, new { id = "testid1", name="firstname" })
</div>
<div>
<label>Last Name</label>
#Html.TextBoxFor(x=>x.LastName, new { id = "testid1", name="lastname" })
</div>
<div>
<label>Email Address</label>
#Html.TextBoxFor(x=>x.EmailAddress, new { id = "testid1", name="emailaddress" })
</div>
<div>
<label>Department</label>
#Html.DropDownListFor( x=> x.GetAllDepartments,new SelectList(Model.GetAllDepartments,"DepartmentId","DepartmentDescription"), new {#class = "mydropdown", name="dept"})
</div>
<div>
<label></label>
<input type="submit" value="submit"/>
</div>
</form>
I want to be able to get the selected value of the department from dropdownListFor box. I am getting null as the selected value.
Please assist. All other values are correct. The code below is part of the controller code. I just decided to separate it.
[HttpPost]
public ActionResult Index(StudentDto objstudent)
{
string strFirstName = objstudent.FirstName;
string strLastName = objstudent.LastName;
string strEmailAddress = objstudent.EmailAddress;
string strDept = Request.Form["dept"];
var displayform = _objStudentService.DisplayStudentInformation();
return View(displayform);
}
A <select> element postback a single value. You cannot bind a <select> to a collection of complex objects (in your case List<DepartmentDto>). Start by creating a view model representing what you want to edit
public class StudentVM
{
[Display(Name = "First Name")]
[Required(ErrorMessage = "Please enter your first name")]
public string FirstName { get; set; }
.... // other properties of StudentDto
[Display(Name = "Department")]
[Required(ErrorMessage = "Please select a department")]
public int SelectedDepartment { get; set; }
public SelectList DepartmentList { get; set; }
}
Next, your StudentDto model should not contain a property containing a collection of all departments. Your use of DropDownListFor() suggest each student has only one Department, therefore the property should be `public DepartmentDto> Department;
Controller
public ActionResult Create()
{
StudentVM model = new StudentVM();
ConfigureCreateViewModel(model);
return View(model);
}
[HttpPost]
public ActionResult Create(StudentVM model)
{
if(!ModelState.IsValid)
{
ConfigureCreateViewModel(model); // reassign the select list
return View(model); // return the view so user can correct errors
}
StudentDto student = new StudentDto()
{
FirstName = model.FirstName,
LastName = model.LastName,
EmailAddress = mdoel.EmailAddress,
Department = db.Departments.Find(model.SelectedDepartment) // modify to suit
}
// save StudentDto and redirect
}
private void ConfigureCreateViewModel(StudentVM model)
{
List<DepartmentDto> departments = // call a service to get a collection of all departments
model.DepartmentList = new SelectList(departments, "DepartmentId","DepartmentDescription");
}
View
#model yourAssembly.StudentVM
#using (Html.BeginForm())
{
#Html.LabelFor(m => m.FirstName)
#Html.TextBoxFor(m => m.FirstName)
#Html.ValidationMessageFor(m => m.FirstName)
.... // other controls of StudentVM
#Html.LabelFor(m => m.SelectedDepartment)
#Html.DropDownListFor(m => m.SelectedDepartment, Model.DepartmentList, "--Please select--")
#Html.ValidationMessageFor(m => m.SelectedDepartment)
<input type="submit" value="submit"/>
}
Side notes:
Use #Html.LabelFor(m => m.FirstName) rather than <label>First
Name</label>. A <label> is an element associated with a control
(clicking on it sets focus to the associated control) - you usage
does nothing because it is missing the for attribute
The html helper methods correctly give the elements an id and
name attribute. In you case you are generating invalid html by
creating duplicate id attributes (the first 3 elements have
id="testid1") and you should never attempt to set the name
attribute (in the first 3 cases, your just setting it to what it
already is anyway, but in the case of the dropdown, you trying to
change it to name="dept" which fortunately does not work - because
if it did, binding would fail!)
You should also consider adding validation attributes to your view
model properties, e.g. [Required(ErrorMessage="Please enter a first
name")] and in the view including #Html.ValidationMessageFor(m =>
m.FirstName)

Delete value by updating field

I have this:
View:
#using (Html.BeginForm())
{
#Html.AntiForgeryToken()
<div class="form-horizontal">
<h4>Bycicle</h4>
<hr />
#Html.ValidationSummary(true)
#Html.HiddenFor(model => model.id)
<div class="form-group">
<label class="control-label col-md-2" for="BycicleID">Mark</label>
<div class="col-md-10">
#Html.DropDownList("BycicleID", String.Empty)
#Html.ValidationMessageFor(model => model.id)
</div>
</div>
The controller:
public async Task<ActionResult> Edit(int? id)
{
if (id == null)
{
return new HttpStatusCodeResult(HttpStatusCode.BadRequest);
}
Bycicle bycicle = await db.Bycicles.FindAsync(id);
if (bycicle == null)
{
return HttpNotFound();
}
ViewBag.id = new SelectList(db.Bycicles, "BycicleID", "Mark", bycicle.id);
//ViewBag.Color = new SelectList(db.Bycicles, "Color", "Color", bycicle.Color);
//ViewBag.Weight = new SelectList(db.Bycicles, "Weight", "Weight", bycicle.Weight);
//ViewBag.Height = new SelectList(db.Bycicles, "Height", "Height", bycicle.Height);
return View(bycicle);
}
// POST: Bycicle/Edit/5
[HttpPost]
[ValidateAntiForgeryToken]
public async Task<ActionResult> Edit(
[Bind(Include = "id, Mark, Color, Weight,Height")]
Bycicle bycicle)
{
if (ModelState.IsValid )
{
db.Entry(bycicle).State = EntityState.Modified;
await db.SaveChangesAsync();
return RedirectToAction("Index");
}
ViewBag.id = new SelectList(db.Bycicles, "id", "Mark", bycicle.id);
return View(bycicle);
}
and the Model:
public class Bycicle
{
public int id { get; set; }
// [Column("Mark")]
public string Mark { get; set; }
public string Color { get; set; }
public string Weight { get; set; }
public string Height { get; set; }
public DateTime? LastTimeChecked { get; set; }
}
But so I can update the other values(Color, Weight, Height) But the Mark name will be deleted if I press save in the Update view. I also checked the db and the Mark value is gone after Update. But If I just press on Edit(update) Then first I see the value(Mark) in the dropdownlist, but after save the mark value is gone. Even if I didnt changed the Mark value in the Update view.
I just cant figure what is wrong.
Thank you!!
Oke,
I did understand it was a type mistake,
But what do you mean with the dropdonlists are not correct? Because you dont have a infinite mark list of bycicles. So that Is why I choose to make a dropdownlist with all the marks and the colors and the sizes. Because an admin fill in the marks, sizes, etc and then the user can select a mark, color, etc. But how will you design the different properties?
I dont have seperate tables for color, mark, etc. But is that necessary?
Thank you
Your not binding anything to the property Mark (what you have shown is bound to the ID property). Preferably the names of your select lists should not be the same as your properties.
In the controller
ViewBag.MarkList = new SelectList(db.Bycicles, "BycicleID", "Mark");
and in the view
#model YourAssembly.Bycicle
....
<div class="form-group">
#Html.LabelFor(m => m.Mark)
<div class="col-md-10">
#Html.DropDownListFor(m => m.Mark, (SelectList)ViewBag.MarkList)
#Html.ValidationMessageFor(m => m.Mark)
</div>
</div>
Note, since you binding all properties, you do not need [Bind(Include = "id, Mark, Color, Weight,Height")]
Edit
While passing values by ViewBag works, I recommend you use view models and strongly typed helpers so you have intellisense support as well as all the other benefits of using view models.
public class BycicleVM
{
public int id { get; set; }
// other properties of Bycicle that you want to edit
public SelectList MarkList { get; set; }
// other select lists
}
then assign the select lists to the view model rather than ViewBag

How can i use Dictionary in MVC4 ViewModel,Controller, View?

I have a ViewModel like below,
public class EnrollPlanPriceLevelViewModel
{
public EnrollPlanPriceLevel EnrollPlanPriceLevels { get; set; }
public Dictionary<PriceLevel,decimal> Prices { get; set; }
}
Code in my View, but I am unable to create View for Prices. Please help me someone!
#{
int i = 0;
foreach (FCA.Model.PriceLevel p in ViewBag.PriceLevelID)
{
i = i + 1;
<div class="span4">
#Html.TextBoxFor(model => model.Prices[p], new { #placeholder = "Price" })
</div>
}
}
I want to call Dictionary object values in Controller how?
ViewModel :
public class EnrollPlanPriceLevelViewModel
{
public EnrollPlanPriceLevel EnrollPlanPriceLevels { get; set; }
public Dictionary<string,decimal> Prices { get; set; }
}
My Controller's Get method should intitialize 'Key' and Values like this. so that you can loop through in View for each KeyValue pair.
Controller's GET method:
public ActionResult Create()
{
var model = new EnrollPlanPriceLevelViewModel();
model.Prices = new Dictionary<string, decimal>();
foreach (PriceLevel p in db.PriceLevelRepository.GetAll().ToList())
{
model.Prices.Add(p.PriceLevelID.ToString(), 0);
}
return View(model);
}
View using Dictionary like this:
<div class="span12">
#{
foreach (var kvpair in Model.Prices)
{
<div class="span4">
#Html.TextBoxFor(model => model.Prices[kvpair.Key], new { #placeholder = "Price" })
#Html.ValidationMessageFor(model => model.Prices[kvpair.Key])
</div>
}
}
</div>
Controller's POST method: presenting dictionary's values
prices is a Dictionary item (e.g. KeyValuePair<PriceLevel, decimal>).
So you must bind each property of the pair: Key and Value separately.

"inline" editing in a mvc 4 list of objects

I have a strange problem and I don't know if this is actually possible.
What I want is, to be able to list all the values from my model and and edit them directly in the list.
Here's what I have:
Model Linker:
public class StoreLinkerModel
{
//public Guid? id { get; set; }
public IEnumerable<Stores> StoresAndOpeninghours { get; set; }
}
public class Stores
{
public long ID { get; set; }
public string StoreName { get; set; }
public string Address { get; set; }
public string Zip { get; set; }
public string City { get; set; }
}
My Controller:
public ActionResult Overview()
{
var model = new StoreLinkerModel
{
StoresAndOpeninghours = new[]
{
new Stores()
{
ID = 0,
Address = "Enghavevej 70"
},
new Stores()
{
ID=1,
Address = "Løngangsgade 30"
},
}
};
return View(model);
}
[HttpPost]
public ActionResult Overview(StoreLinkerModel model)
{
if (ModelState.IsValid)
{
var x = "go go go";
}
return RedirectToAction("Overview");
}
My overview.aspx page:
#model streetoffrs.web.Models.StoreLinkerModel
#{
ViewBag.Title = "Overview";
Layout = "~/Views/Shared/_dashboard.cshtml";
}
#Html.EditorFor(x => x.StoresAndOpeninghours)
and my EditorTemplate stores.aspx
#model streetoffrs.web.Models.Stores
#using (Html.BeginForm("Overview", "Dashboard", FormMethod.Post, new { name = "id" + #Html.DisplayFor(m => m.ID) }))
{
#Html.EditorFor(x => x.Address)
<input type="submit" class="left btn btn-primary" value="Ret butiksdata">
}
<br />
The list is being generated as it should, and when I hit the first button at the first editorfor it will post the model to my controller, but when I push the 2nd button, the model is null, but the first button still works!
Is this possible at all, if yes what am I missing, if not, tell me how I can accomplish this.
thanks in advance!
you need edit post action like this:
[HttpPost]
public ActionResult Overview(StoreLinkerModel model)
{
if (ModelState.IsValid)
{
var x = "go go go";
}
return View(model);
}
the RedirectToAction will be go to the first Overview Action,so you will be lost the data.