Mapping list of checked InputCheckbox elements to list of string on the form model - data-binding

I have a list of strings that I'd like to list in a form. Users should be able to check the boxes for the strings they want and I'd like to bind the list values back to the form model.
Let's take a look at the code I've figured out so far:
//mypage.razor
//...
<EditForm Model="MyModel">
#foreach(var opt in AvailableOptions)
{
<label for="option-#opt">#opt</label>
<InputCheckbox id="option-#opt" name="option-#opt" type="checkbox" #bind="#(/* bind to what?!? */)"/>
}
</EditForm>
#code
{
private MyPageModel MyModel = new ();
private List<string> AvailableOptions = new List<string>
{
"Apple",
"Banana",
"Cherry"
}
public class MyPageModel
{
public List<string> SelectedValues { get; set; } = new();
}
}
So this is where I started at. Of course, while I can show the value of the label as part of the loop, it's not clear how I'd bind the boolean value of the Checked property to the form model, especially not when I'm wanting to save the opt string value to the form model's list (for checked values) and not a collection of boolean values.
Looking at an answer to a similar question, the thought is that I'd create a "carrier" class with the name and a boolean like:
public class MyCheckedOption
{
public string Name {get; set;}
public bool IsChecked {get; set;}
}
Now, when I bind in the InputCheckbox, I can now set AvailableOptions to a list of MyPageModel and do #bind="opt.IsChecked", but this now binds to MyPageModel and doesn't bind back to my form model.
Now, in my OnValidSubmit, I could harvest the values of these and populate my form model, but that doesn't seem ideal.
Rather, is there some way to map the boolean of the checked properties (as populated by something in my code behind) to a list of string (wherein the value I want to use is another property of the "carrier" class I'm looping through a list of) that I can store directly on the form model?

You can use Linq's Select method to convert your list to something else-- in the following case, a list of MyCheckableOption objects. Later, when you want to do something with the list, you can do the same in reverse to get back to a List<string>
#foreach (var opt in AvailableOptions)
{
<label>#opt.Name </label>
<input type="checkbox" #bind="opt.IsChecked" />
<br/>
}
<hr />
#foreach (var item in AvailableOptions.Where(option => option.IsChecked))
{
<div>#item.Name has been selected. </div>
}
#code
{
private List<MyCheckableOption> AvailableOptions = new List<string>
{
"Apple",
"Banana",
"Cherry"
}
.Select(option => new MyCheckableOption {Name = option }).ToList();
public class MyCheckableOption
{
public string Name { get; set; }
public bool IsChecked { get; set; }
}
}

Related

ASP.NET MVC view calculate for a column

I have a view model, I have a list from a table in my view model, I'm binding the model to my view and bind the list to an html table.
View model:
public IEnumerable<MyTable> TableObject { get; set; }
View:
#if (Model.TableObject != null)
{
foreach(var item in Model.TableObject)
{
<td>#item.Column1</td>
<td>#item.Column2</td>
<td>CalculatedVariable</td>
}
}
I can get all of my table column values like Column1, Colum2. But I want to calculate a value for display. I can get this value in the controller with a method like this:
Controller:
public string GetCalculateValue(List<MyTable> searchList, int compareValue)
{
string returnValue = String.Empty;
var _theList = searchList.Where(x => x.myValue == compareValue).ToList();
if (_theList.Count() > 1)
{
returnValue = "OK";
}
return returnValue;
}
I want to bind that returnValue to my view for display in a column in the html table. How can I pass this string value for my table rows? I hope I could explain.
Thanks for help.
Its hard to see what's going on but I believe your general approach needs to be as follows. Add a property to your MyTable class so that it looks like this
public class MyTable
{
public string Column1 {get; set;}
public string Column2 {get; set;}
public int myValue {get; set;}
public string CalculatedVariable {get; set;}
}
Then foreach MyTable object that you have set the value of CalculatedVariable in the controller. Then you will be able to display Calculated variable like your other properties.
Not what you asked but I think your GetCalculateValue can be made more readable if it is changed to this.
public string GetCalculateValue(List<MyTable> searchList, int compareValue)
{
return searchList.Any(x => x.myValue == compareValue) ? "OK" : "";
}

ASP.NET MVC ListBox does not show the selected list items

I am in a big trouble. I read 4 stackoverflow question and one blogpost. I have tried 5 different approach to view the selected items in a multiple selectlist.
I have no success.
The multiple selectlist is generated, but it does not select the items. I have no more idea.
Model:
public class EditableModel
{
public IList<Company> SelectedCompanies { get; set; }
public IList<SelectListItem> SelectListCompanies { get; set; }
}
Controller:
public ActionResult Edit(int id)
{
var service = _serviceDAL.GetEditableModel(id);
if (service!= null)
{
service.SelectListCompanies = GetSelectListCompanies(service.SelectedCompanies);
return View(service);
}
}
private IList<SelectListItem> GetSelectListCompanies(IList<Company> selectedCompanies)
{
List<SelectListItem> items = new List<SelectListItem>();
foreach (Companycompany in _companyService.GetCompanies())
{
items.Add(new SelectListItem
{
Value = company.CompanyId.ToString(),
Text = company.Name,
Selected = selectedCompanies.Any(x => x.CompanyId == company.CompanyId)
});
}
return items;
}
View
#Html.ListBox("SelectedCompanies", Model.SelectListCompanies, Model.SelectedCompanies.Select(x => x.CompanyId.ToString()) )
And nothing. The items in the select list is not selected...
I have tried this Multiselect, the same result, or this one as the current solution.
You cannot bind a <select multiple> to a collection of complex objects. It binds to, and posts back an array of simple values (the values of the selected options).
Your SelectedCompanies property needs to be IEnumerable<int> (assuming the CompanyId of Company is also int). Note also the Selected property of SelectListItem is ignored when binding to a property.
Your also using the same collection for the selected Companies and the list of all Companies which makes no sense. Your SelectListCompanies should be generated from your table of Company.
Model
public class MyViewModel
{
public IEnumerable<int> SelectedCompanies { get; set; }
public IEnumerable<SelectListItem> SelectListCompanies { get; set; }
}
Base on your current code for EditableModel, your code should be
public ActionResult Edit(int id)
{
var service = _serviceDAL.GetEditableModel(id);
....
MyViewModel model = new MyViewModel
{
SelectedCompanies = service.SelectedCompanies.Select(x => x.CompanyId),
SelectListCompanies = GetSelectListCompanies()
};
return View(model);
private IEnumerable<SelectListItem> GetSelectListCompanies()
{
var all companies = ... // call method to get all Companies
return companies.Select(x => new SelectListItem
{
Value = x.CompanyId.ToString(),
Text = x.Name
});
}
However, it look like you should be modifying your EditableModel and the GetEditableModel() code to return the correct data in the first place.

Count how many elements of an item and return to a view

I have a Database where I have a table cars that has some cars, and each devices has a type. I want to make a view to see how many cars of each type I have in the table. What I have till now is, in controller.
Controller:
public ActionResult CountCars()
{
var count = db.Cars.Where(s => s.Cars.Name.Contains("Ford")).Count();
var view = new CountCarsViewModel()
{
Count = count
};
return PartialView("_MainSideBarPartialLayout", view);
}
ViewModel class:
public class CountCarsViewModel
{
public int Count { get; set; }
}
View:
#model Project.ViewModels.Home.CountCarsViewModel
<span class="badge">#Model.Count</span>
But it wont count any cars.. Just getting 0.
Anyone can help, with a solution?
Your current query is returning 0 probably because there is no matching Car with Name Ford you will have to debug that and see what's happening. To answer how many cars of each type I have in the table you need GroupBy:-
var view= db.Cars.GroupBy(s => s.Cars.Name)
.Select(x => new CountCarsViewModel
{
CarName = x.Key,
Count = x.Count()
});
return PartialView("_MainSideBarPartialLayout", view);
Change you ViewModel to include a property to hold CarName like this:-
public class CountCarsViewModel
{
public string CarName {get; set; }
public int Count { get; set; }
}
I think the problem is using "PartialView" in "return PartialView("_MainSideBarPartialLayout", view);". Try it on normal view to see the result and then make it partial. If you insist to use partial view , probably you need a trigger for partial view to show correct count.

How to create a radiobutton group using an editor template in Razor

I have the following model
public class FilterSetting
{
public FilterType Type { get; set; }
public ShowOption Option { get; set; }
public bool IsMultiple { get; set; }
public List<int> SelectedValues { get; set; }
public List<SelectListItem> Values { get; set; }
public int RowCount { get; set; }
}
public enum ShowOption
{
Common,
Also,
All
}
I want to create a radio button group for the ShowOption enum, but I want to display that group using an editor template because I have another model that creates a list of FilterSetting and it will display about 7 FilterSettings each of one must have a group of 3 radio buttons for the ShowOption property.
The problem is when razor is rendering the radio buttons from the editor template it uses the same name for every radio button (name="filter.Option") and I don't know how to set the value.
This is my editor template
#model Models.FilterSetting
#Html.RadioButtonFor(f => f.Option, "Common", new { id = ""+ Model.Type })
#Html.Label(""+Model.Type, "Show only common assets")
<br />
#Html.RadioButtonFor(f => f.Option, "Also", new { id = "" + Model.Type })
#Html.Label(""+Model.Type, "Also show assets matching the values selected below")
<br />
#Html.RadioButtonFor(f => f.Option, "All", new { id = "" + Model.Type })
#Html.Label(""+Model.Type, "Show all assets")
<br />
#if (Model.IsMultiple)
{
#Html.ListBoxFor(f => f.SelectedValues, Model.Values)
}
else
{
#Html.DropDownListFor(f => f.SelectedValues, Model.Values, new { size = "4" })
}
I tried passing the name on the htmlAttributes object but it doesn't work.
EDIT:
Apparently the issue is the way I am calling the editor.
I'm calling it in this way
#foreach (var filter in Model.FilterSettings)
{
....
#Html.EditorFor(f => filter)
}
And when I call it like this
#Html.EditorFor(f => f.filterSettings)
The radio buttons work properly. What's happening when I do the for each?
Thanks for all the help!
When you call the Editor/EditorFor for a collection Razor will keep track of the names and ids generated and so you will get the names generated as for ex. Addresses[0].Line1, Addresses[1].Line1...
But when you iterate the collection yourself and call the editor for the each model razor don't keeps the track for the names and ids (how should it be? is that won't be more complicated?) and it's thinks as a new control going to be rendered in the page.
Usually I use an #Html.HiddenFor(x=>x.id) and #Html.HiddenFor(x=>x.name), try this

Simple DropDownList in ASP.NET MVC3 app

I need simple DropDownList in form and I don't want to create something like ViewModel.
I have two models(tables) in relation 1:n:
public class Course
{
public int ID { get; set; }
public string Name { get; set; }
}
and
public class Project
{
public int ID { get; set; }
public int CourseId { get; set; }
public int ProjectNo { get; set; }
public string Name { get; set; }
public DateTime Deadline { get; set; }
}
In the 'Create Project' I want to have DropDownList with Id (as value) and Name(as text) from Course table(model). In the new project will be insert chosen CourseId. How can I do that as simple as possible?
Any particular reason why you don't want to use a ViewModel? They're very helpful for this type of problem.
If you don't want to use a ViewModel, then you can construct a specific class in your controller that is an aggregate of the properties you need from both classes:
public ActionResult Show(int id)
{
Course course = repository.GetCourse(id); // whatever your persistence logic is here
Project project = projectRepository.GetProjectByCourseId(id);
string CourseName = from c in course where
c.ID == project.courseID
select c.Name;
IEnumerable<SelectListItem> selectList =
from c in course
select new SelectListItem
{
Selected = (c.ID == project.CourseId),
Text = c.Name,
Value = project.CourseId.ToString()
};
//add the selectList to your model here.
return View(); //add the model to your view and return it.
}
It would be far easier to have a ViewModel for this, so you could have a strongly typed view. Let me show you:
public class ProjectCourseViewModel
{
public SelectList ProjectCourseList {get; private set; }
public Project Project {get; private set; }
public Course Course {get; private set; }
public ProjectCourseViewModel(Project project, Course course)
{
ProjectCourseList = GetProjectCourseSelectList(project, course)
Project = project;
Course = course;
}
private SelectList GetProjectCourseSelectList(Project project, Course course)
{
IEnumerable<SelectListItem> selectList =
from c in course
select new SelectListItem
{
Selected = (c.ID == project.CourseId),
Text = c.Name,
Value = project.CourseId.ToString()
};
}
}
And then your controller would be really simple:
public ActionResult Show(int id)
{
Course course = repository.GetCourse(id);
Project project = projectRepository.GetProjectByCourseId(id);
ProjectCourseViewModel pcvm = new ProjectCourseViewModel(project, course)
return View(pcvm);
}
And then your view takes in a strongly typed model, and you don't have to rely on ViewData, which is a Good Thing.
Note: I haven't compiled this, just written it. There are probably compilation bugs.
probably you could solve it using the following example:
in your controller include a Viewbag
{
Viewbag.Course = db.course.ToList();
var project = new project.....
}
And in your View use the following pattern:
#Html.DropDownList("CourseId",
new SelectList(ViewBag.Course as System.Collections.IEnumerable,
"CourseId", "Name", Model.ID))
where each field represent:
•The name of the form field (CourseId)
•The list of values for the dropdown, passed as a SelectList
•The Data Value field which should be posted back with the form
•The Data Text field which should be displayed in the dropdown list
•The Selected Value which is used to set the dropdown list value when the form is displayed
more info at: http://www.asp.net/mvc/tutorials/mvc-music-store-part-5
brgds.
In the Controler:
var CourseName = from c in course where
c.ID == project.courseID
select c.Name;
SelectList sl = new SelectList(CourseName);
ViewBag.names= sl;
in the view :
#Html.DropDownList("Name", (SelectList)ViewBag.names)

Resources