Radio Button For multiple bools - asp.net

Say I have the following properties in my model that I want to be mutually exclusive:
public bool PrintWeek1 {get; set;}
public bool PrintWeek2 {get; set;}
public bool PrintWeek3 {get; set;}
Is it possible to render these as a set of radio buttons or do I need to change them to an enum?
If I use #Html.RadioButtonFor it renders name as the name of the property so they aren't grouped correctly.

Here comes a quick solution, let you have following properties in Model -
public bool PrintWeek1 { get; set; }
public bool PrintWeek2 { get; set; }
public bool PrintWeek3 { get; set; }
public string SelectedValue { get; set; }
Then your HTML should be like this -
#Html.RadioButtonFor(Model => Model.PrintWeek1, "PrintWeek1", new { #Name = "SelectedValue" })
#Html.RadioButtonFor(Model => Model.PrintWeek2, "PrintWeek2", new { #Name = "SelectedValue" })
#Html.RadioButtonFor(Model => Model.PrintWeek3, "PrintWeek3", new { #Name = "SelectedValue" })
Then when you submit the form, you will get the selected value in SelectedValue property.
EDIT
To Address #StephenMuecke point, created the below solution -
Create a enum -
public enum PrintWeekType
{
PrintWeek1, PrintWeek2, PrintWeek3
}
Then have a model property (instead of individual properties, have single emum property) -
public PrintWeekType SelectedValue { get; set; }
HTML should be like below -
#Html.RadioButtonFor(m => m.SelectedValue, PrintWeekType.PrintWeek1)
#Html.RadioButtonFor(m => m.SelectedValue, PrintWeekType.PrintWeek2)
#Html.RadioButtonFor(m => m.SelectedValue, PrintWeekType.PrintWeek3)
Using above sample, one can pre-select a radiobutton, at the same time we can post the selected value in SelectedValue property.

Ok I abandoned the bools and just ended up using a list - this seemed to be the quickest and easiest way to do it.
Where I initialize my model:
public PrintViewModel()
{
this.PrintTypes = new List<string>() { "Print Week 1", "Print Week 2", "Print Week 3" };
}
public List<string> PrintTypes { get; set; }
public string SelectedPrintType { get; set; }
In my view (I wanted the first option selected by default):
#for(int i = 0; i < Model.PrintTypes.Count; i++)
{
<div class="row">
<div class="col-md-2">
#(i == 0 ? Html.RadioButtonFor(x => x.SelectedPrintType, Model.PrintTypes[i], new {#checked = "checked"}) : #Html.RadioButtonFor(x => x.SelectedPrintType, Model.PrintTypes[i]))
<label for="#Model.PrintTypes[i]">#Model.PrintTypes[i]</label>
</div>
</div>
}

Related

Blazorise Datagrid inline edit for complex object

The Blazorise Datagrid supports inline editing. In my code, the basic editing works fine but when an object is used as a property in my parent object, editing does not work as expected.
Below, the city the value not updated as expected. What is missing to allow for a proper edit?
Code
<DataGrid Data="forecasts" TItem="WeatherForecast" EditMode="Blazorise.DataGrid.DataGridEditMode.Inline">
<DataGridCommandColumn TItem="WeatherForecast" CellsEditableOnEditCommand="true"></DataGridCommandColumn>
<DataGridDateColumn TItem="WeatherForecast" Field="#nameof(WeatherForecast.Date)" Caption="Date" Editable="true"></DataGridDateColumn>
<DataGridDateColumn TItem="WeatherForecast" Field="#nameof(WeatherForecast.Temperature)" Caption="Temperature" Editable="true"></DataGridDateColumn>
<DataGridSelectColumn TItem="WeatherForecast" Field="#nameof(WeatherForecast.City)" Caption="City" Editable="true">
<DisplayTemplate>
#{
var name = (context as WeatherForecast).City?.Name;
#name
}
</DisplayTemplate>
<EditTemplate>
#{
<Select TValue="City"
SelectedValue=
"#((City)(((CellEditContext)context).CellValue))"
SelectedValueChanged=
"#( v => ((CellEditContext)context).CellValue = v)">
#foreach (var item in Cities)
{
<SelectItem TValue="City" Value="#(item)">
#item.Name
</SelectItem>
}
</Select>
}
</EditTemplate>
</DataGridSelectColumn>
</DataGrid>
Code Section
#code {
private List<WeatherForecast> forecasts;
private List<City> Cities;
protected override async Task OnInitializedAsync()
{
forecasts = await ForecastService.GetForecastAsync(DateTime.Now); // get list of forecast
Cities = await ForecastService.GetCityListAsync(); // get list of cities
}}
Model classes
public class WeatherForecast
{
public int Id { get; set; }
public DateTime Date { get; set; }
public int Temperature { get; set; }
public City City { get; set; }
}
public class City
{
public int Id { get; set; }
public string Name { get; set; }
}
Try this workaround since Select component doesn't support complex objects binding:
<EditTemplate>
<Select
TValue="int"
SelectedValue="#((int)((City)(((CellEditContext)context).CellValue)).Id)"
SelectedValueChanged=
"#( v => ((CellEditContext)context).CellValue = Cities.First(x=> x.Id == v))">
#foreach (var item in Cities)
{
<SelectItem TValue="int" Value="#(item.Id)">#item.Name</SelectItem>
}
</Select>
</EditTemplate>

DropdownList value doesnt add to database

I can display the values from my database both in a dropdownlist and where the value is needed.
But I can't get the value from the dropdownlist to my database while creating something. it's getting null.
I've tried some solutions from s.o.f but they didnt't work.
Models 1:
public class Kategori
{
[Key]
public int KategoriID { get; set; }
public string Namn { get; set; }
}
Models 2:
public class Inlägg
{
[Key]
public int InläggsID { get; set; }
public Kategori Kategori { get; set; }
}
Controller:
// POST: Inlägg/Create
[HttpPost]
[ValidateAntiForgeryToken]
public async Task<IActionResult> Create([Bind("Titel,Text,Kategori.Namn")] Inlägg inlägg)
//The Kategori is getting null
{
if (ModelState.IsValid)
{
inlägg.Datum = DateTime.Now;
_context.Add(inlägg);
await _context.SaveChangesAsync();
return RedirectToAction(nameof(Index));
}
return View(inlägg);
}
View:
#Html.DropDownList("Kategori", null, htmlAttributes: new { #class = "form-control" })
I've tried using SelectItemList, select with options values, having a SelectItem inside Models class also a "public Kategori List" inside Inlägg.
Don't really know how to solve this. I've just tried 8 hours today, and 2 hours yesterday.
How can I get the value that the user choosen in the dropdownlist instead of getting null? Tell me if I need to send more codes :-)
You should change it;
#Html.DropDownList("Kategori", null, htmlAttributes: new { #class = "form-control" })
to
#Html.DropDownList("SelectedCategory", ViewData["Kategori"] as SelectList, htmlAttributes: new { #class = "form-control" })
The selected dropdown element is passed to serverside as SelectedCategory.
Also, I strongly suggest you to use Model classes instead of ViewData to carry data between controller and view.
You need to add another property for the foreign key value. Since your other related entity class name is Kategori, you may name this new property KategoriId so that it matches the convention for the foreign key property names.
public class Inlagg
{
[Key]
public int InläggsID { get; set; }
public string Titel { get; set; }
public string Text { get; set; }
public DateTime Datum { get; set; }
public virtual Kategori Kategori { get; set; }
public int? KategoriId { set;get;} // This is the new property
}
Now in your form inside your view, make sure the select element rendered by the DropDownList helper has the same name attribute value as the new property name (check the view source of the page)
#Html.DropDownList("KategoriId", ViewData["Kategori"] as SelectList)
Now finally, make sure you include this new input name/property name inside the Bind attributes Include list so that the model binder will bind that.
public async Task<IActionResult> Create([Bind(Include="Titel,Text,KategoriId")]
Inlagg inlagg)
{
// to do : your code for saving and returning something
}
Another option is to use a view model with only needed properties, instead of using the Bind attribute with your entity class

#Html.DisplayNameFor not showing data MVC5

I have searched around and not had much luck finding a solution to my exact problem.
Model
public class PageDetailsViewModel
{
public int Id { get; set; }
public string Name { get; set; }
public string Description { get; set; }
public string Image { get; set; }
}
Controller
public ActionResult Search(int SysID)
{
var query = from r in _db.Auctions
from d in _db.Product_Details
where SysID == d.Id && r.BidStatus == "Open" && d.Id == r.Product_DetailsId
select new PageDetailsViewModel
{
Name = d.Name,
Description = d.Description,
Image = d.Image
};
return View(query);
}
View
#model IEnumerable<ProjectT.Models.PageDetailsViewModel>
#Html.DisplayNameFor(x => x.Name)
This fails to bring the name through. However, if I use a foreach
#foreach (var item in Model)
{
#item.Name
}
It brings through the name no problem.
Any help is much appreciated.
This extension method shows the value of the DisplayNameAttribute from DataAnnotations namespace. Consider this a label. Typically it is used like this:
[DisplayName("The Name")]
public string Name { get; set; }
And in the view:
#Html.DisplayNameFor(x => x.Name) <-- displays The Name
The code above will work only if the model is a single item. For the list case, as you have, you need to do some tricks, say a for loop, so you could do something like:
#Html.DisplayNameFor(x => x[i].Name): #Model[i].Name <-- displays The Name: Bill

#Html.DropDownListFor not posting back to controller

I am using #Html.DropDownListFor for the first time. Code is below.
Model:
class Student
{
[Required]
[Display(Name = "Name")]
public string Name { get; set; }
[Required]
[Display(Name = "Roll Number")]
public string RollNumber { get; set; }
[Required]
[Display(Name = "ClassId")]
public int ClassId { get; set; }
}
class Class
{
[Required]
[Display(Name = "ClassId")]
public string RollNumber { get; set; }
[Required]
[Display(Name = "ClassName")]
public string RollNumber { get; set; }
}
Controller:
public ActionResult Create()
{
Student student = new BusinessEntities.Student();
List<Class> classes = GetAllClasses();
ViewBag.ClassId = new SelectList(classes, "ClassId", "ClassName");
return View(student);
}
[HttpPost]
public ActionResult Create(BusinessEntities.Student student)
{
if (ModelState.IsValid)
{
//Integer has 0 by default. But in our case if it contains 0,
//means no class selected by user
if(student.ClassId==0)
{
ModelState.AddModelError("ClassId", "Select Class to Enroll in");
return View(student);
}
}
}
Student Create View:
<form method="post">
Select Class :
#Html.DropDownListFor(Model=>Model.ClassId,ViewBag.ClassId as IEnumerable<SelectListItem>, "ClassId","ClassName")
#Html.ValidationMessageFor(Model => Model.ClassId)
<input type="submit" value="Submit" />
</form>
Error Message:
The ViewData item that has the key 'ClassId' is of type 'System.Collections.Generic.List`1[[BusinessEntities.Class, BusinessEntities, Version=1.0.0.0, Culture=neutral, PublicKeyToken=null]]' but must be of type 'IEnumerable'.
I want ClassId of Student be binded and populated automatically when posted back to Controller. Please help me to get rid of it.
Thanks.
You need to give the SelectList a different name that the property your binding to (say)
ViewBag.ClassList = new SelectList(classes, "ClassId", "ClassName");`
and then
#Html.DropDownListFor(m => m.ClassId, ViewBag.ClassList as IEnumerable<SelectListItem>)
and then ensure if you return the view (for example if ModelState is invalid), that you repopulate the SelectList (as you have done in the GET method). Currently when you return the view, it is null resulting in an error, because if the second parameter is null the fallback is that the helper expects the first parameter to be IEnumerable<SelectListItem> (but its not - its typeof int)
Side notes: Do not use Model => Model.XXX (capital M) and your current use of DropDownistFor() as 2 parameters which make no sense. "ClassId" will add a label option <option value="">ClassId</option> and the last one ,"ClassName" will not do anything.
Edit
In addition, your
if(student.ClassId==0)
{
ModelState.AddModelError("ClassId", "Select Class to Enroll in");
return View(student);
}
is a bit pointless. student.ClassId will never be 0 unless one of the items in your GetAllClasses() has ClassId = 0. You should be using
[Required(ErrorMessage = "Select Class to Enroll in")] // add error message here
public int ClassId { get; set; }
and in the view
#Html.DropDownListFor(m => m.ClassId, ViewBag.ClassList as IEnumerable<SelectListItem>, "--please select--")
which will create the first option with a value of null. If this option were selected, then the DefaultModelBinder will attempt to set the value of ClassId = null which fails (because typeof int cannot be null) and a ModelState error is added and ModelState becomes invalid.
The in the POST method
[HttpPost]
public ActionResult Create(BusinessEntities.Student student)
{
if (!ModelSTate.IsValid)
{
ViewBag.ClassList = // repopulate select list
return View(student);
}
// Save and redirect
}

Umbraco: Create CheckBoxList property with prevalues from mvc model

What I want to do is create a CheckBoxList property so the editor could choose facilities specific for current page (hotel name) in BO, and render content based on what is checked.
I've created a model:
public class Facility
{
public int Id { get; set; }
public string Description { get; set; }
public string IconUrl { get; set; }
public List<Facility> GetFacilities()
{
return new List<Facility>()
{
new Facility() { Id = 4, Description = "Free parking", IconUrl = "" },
new Facility() { Id = 6, Description = "Spa", IconUrl = "" },
new Facility() { Id = 7, Description = "Free Wifi", IconUrl = "" },
new Facility() { Id = 2, Description = "Tennis", IconUrl = "" },
new Facility() { Id = 9, Description = "Room service", IconUrl = "" },
new Facility() { Id = 10, Description = "Fitness", IconUrl = "" }
};
}
}
How can I create a CheckBoxList with the values set in GetFacilities() method? Or should I create a new class in AppCode folder with this method? Where is the best place to put this kind of functionality, and how can I achieve this?
Your Facility model should contain a boolean value to indicate if its been selected
public class FacilityVM
{
public int Id { get; set; }
public string Description { get; set; }
public bool IsSelected { get; set; }
{
public class HotelVM
{
public int ID{ get; set; }
....
public List<FacilityVM> Facilities { get; set; }
}
Controller
public ActionResult Edit(int ID)
{
HotelVM model = new HotelVM();
model.Facilities = // populate the list of available facilities
// Get the hotel from repository and map properties to the view model
return View(model);
}
public ActionResult Edit(HotelVM model)
{
...
foreach(FacilityVM facility in model.Facilities)
{
if (facility.IsSelected)
{
// do something
}
}
....
}
View
#model HotelVM
#using (Html.BeginForm())
{
// render properties of hotel
....
for (int i = 0; i < Model.Facilities.Count; i++)
{
#Html.HiddenFor(m => m.Facilities[i].ID);
#Html.HiddenFor(m => m.Facilities[i].Description);
#Html.CheckBoxFor(m => m.Facilities[i].IsSelected)
#Html.LabelFor(m => m.Facilities[i].IsSelected, Model.Facilities[i].Description)
}
<input type="submit" value="Save" />
}
I think you're thinking about this the wrong way as suggested by Stephen (unless I am misunderstanding your question). You are creating a list of key/value pairs and only one will be selected in the BO and so only one will published to the front-end (regardless of the use of it).
So, in the BO you only need a dropdown list with the key/values pairs. You can create this with the "Dropdown list (publishing keys)" datatype. Also consider using the "SQL dropdown" list datatype as this would give you far more flexibility.
If you then need to convert the selected ID into a Facility object, do this separately using a class implementing the IPropertyEditorValueConverter interface. See here for more information:
http://our.umbraco.org/documentation/extending-umbraco/Property-Editors/PropertyEditorValueConverters

Resources