Radiobutton acting like a checkbox MVC - c#

With the code below, i can select multiple radio buttons at the same time, that is a problem, a true radio button only works with ONE selected item. How do i re-arrange my code so that it acts like a real radio button and not like a checkbox like the code below?
for (int i = 0; i < Model.RadioButtonItems.Count; i++)
{
<div>
#Html.HiddenFor(m => m.RadioButtonItems[i].RBName)
#Html.LabelFor(l => l.RadioButtonItems[i].RBIsSelected, Model.RadioButtonItems[i].RBName)
#Html.RadioButtonFor(r => r.RadioButtonItems[i].RBIsSelected, true);
</div>
}
The rest of code:
Model:
public class ModelVariables
{
public List<Item> RadioButtonItems { get; set; }
}
public class Item
{
public string RBName { get; set; }
public bool RBIsSelected { get; set; }
}
public static class Repository
{
public static List<Item> RBFetchItems()
{
return new List<Item>()
{
new Item() {RBName = "Metal"},
new Item() {RBName = "Jazz"},
new Item() {RBName = "Trance"}
};
}
}
Controller:
var selectedRBItems = model.RadioButtonItems.Where(x => x.RBIsSelected).Select(x => x.RBName).ToList();
if (model.RadioButtonItems != null && selectedRBItems.Count > 0)
{
ViewBag.RBResults = "Successfully Logged Pressed RB's!";
}
else
{
ViewBag.RBResults = "You must select a radio button!";
}
Summary: this code let's you select multiple radiobuttons, i DONT want that, i want only one possible selection out of many options.

Each radio button has a different name attribute so they are not grouped. Your model needs a property to bind the selected value to, and a collection of items for the options
public class ModelVariables
{
[Required(ErrorMessage = "...")]
public string SelectedValue { get; set; }
public List<string> Options { get; set; }
}
and in the GET method
var model = new ModelVariables()
{
Options = new List<string>() { "Metal", "Jazz", "Trance" },
SelectedValue = ? // set this if you want one of the buttons initially selected
};
return View(model);
and in the view
foreach (var option in Model.Options)
{
<label>
#Html.RadionButtonFor(m => m.SelectedValue, option, new { id = "" })
<span>#option</span>
</label>
}
// add the following if you do not set an initial value in the GET method
#Html.ValidationMessageFor(m => m.SelectedValue)

Related

Is it possible to use link inside DropDownList html helper?

I have a model class named categories that retrieves data from database :
public class HomeController : Controller
{
private StoreContext db;
public HomeController()
{
db = new StoreContext();
}
public ActionResult Categories()
{
return View(db.Categories.ToList());
}
}
I want to use DropDownList helper method to display them in the view and I want all the categories inside it to be clickable, say, when you click them it has to adress you to the specified url belongs to the clicked category. Is there a way to make this happen with DropDownList helper? if yes then how?
You can do this but you have to use Jquery . If you ask how?
For example:
My sample entity
public class Category
{
public int Id { get; set; }
public string Url{ get; set; }
public string Name { get; set; }
}
My action:
public IActionResult Categories()
{
var list = new List<Category>();
for (int i = 0; i < 10; i++)
{
list.Add(new Category(){Id = i, Url = "https://stackoverflow.com", Name = "stackoverflow" });
}
var selectList = list.Select(x => new SelectListItem() {Value = Url, Text = x.Name})
.ToList();
return View(selectList);
}
in my View:
#Html.DropDownList("url",Model, "Choose a URL", new { id = "url_list" })
and then using jquery you could subscribe for the change event of this dropdownlist and navigate to the corresponding url:
$(function() {
$('#url_list').change(function() {
var url = $(this).val();
if (url != null && url != '') {
window.location.href = url;
}
});
});

ASP.NET MVC one of the forms dont get validation messages

My problem is this: I have created a view in which I want to be able to remove and add new identity roles. For that I created two forms that call two different actions. I have created a big model which consists of smaller models which are bound by the forms to the actions. Everything works as intended, models get bound properly, data is there and proper actions are executed as they should.
Don't get me wrong, I understand those are separate forms and I know they will never show validation messages both at the same time because only one form can be posted at a time. The problem is that when I click submit on the CreateNewRole form, the validation message is there, but when I click submit on the RemoveRoles action, I don't get any validation messages and no validation classes are applied to the html elements, there is the usual "field-validation-valid" and no "field-validation-error" class in it while its perfectly present in CreateNewRole.
Why does validation work on the first form but not on the second form? I cant find any difference in how i made those two forms, am i not noticing something?
When I debug modelstate of the RemoveRoles action, the error is there, but somehow the view isn't getting informed of it.
View
#model Models.ViewModels.RolePanelViewModel
#using Extensions
<h2>Role Panel</h2>
<article>
<div class="admin-panel-flex-container">
<div class="form-container">
#using (Html.BeginForm("CreateNewRole", "Administrator"))
{
<div class="form-group">
#Html.LabelFor(l => l.NewRoleRolePanelViewModel.NewIdentityRole.Name)
#Html.TextBoxFor(t => t.NewRoleRolePanelViewModel.NewIdentityRole.Name)
#Html.ValidationMessageFor(t => t.NewRoleRolePanelViewModel.NewIdentityRole.Name)
<button type="submit">Dodaj role</button>
</div>
}
</div>
<div class="form-container">
#using (Html.BeginForm("RemoveRoles", "Administrator"))
{
<div class="form-group">
#Html.LabelFor(l => l.ListRolePanelViewModel.SelectedIdentityRoles)
#Html.ListBoxFor(l => l.ListRolePanelViewModel.SelectedIdentityRoles, #Model.ListRolePanelViewModel.IdentityRolesSelectListItems)
#Html.ValidationMessageFor(t => t.ListRolePanelViewModel.SelectedIdentityRoles)
<button type="submit">Skasuj wybrane</button>
</div>
}
</div>
</div>
</article>
Models
public class RolePanelViewModel
{
public ListRolePanelViewModel ListRolePanelViewModel { get; set; }
public NewRoleRolePanelViewModel NewRoleRolePanelViewModel { get; set; }
}
public class ListRolePanelViewModel
{
public List<IdentityRoleDTO> IdentityRoles { get; set; }
public List<SelectListItem> IdentityRolesSelectListItems { get; set; }
[Required(ErrorMessage = "Należy wybrać przynajmniej jedną pozycję z listy")]
public List<string> SelectedIdentityRoles { get; set; }
}
public class NewRoleRolePanelViewModel
{
public IdentityRoleDTO NewIdentityRole { get; set; }
}
public class IdentityRoleDTO
{
public string Id { get; set; }
[Required(ErrorMessage = "Nowa rola musi mieć nazwę")]
[MinLength(5)]
public string Name { get; set; }
public List<IdentityUserRole> Users { get; set; }
}
Actions
public ActionResult OpenRolePanel()
{
var roles = _context.Roles.ToList();
var viewModel = new RolePanelViewModel
{
ListRolePanelViewModel = new ListRolePanelViewModel
{
IdentityRolesSelectListItems = GetSelectListItems(roles,
(a) => new SelectListItem {Value = a.Id.ToString(), Selected = false, Text = a.Name})
},
NewRoleRolePanelViewModel = new NewRoleRolePanelViewModel()
};
return View("RolePanel", viewModel);
}
[HttpPost]
public async Task<ActionResult> CreateNewRole(NewRoleRolePanelViewModel newRoleRolePanelViewModel)
{
if(!ModelState.IsValid)
{
var roles = _context.Roles.ToList();
var viewModel = new RolePanelViewModel
{
ListRolePanelViewModel = new ListRolePanelViewModel
{
IdentityRolesSelectListItems = GetSelectListItems(roles,
(a) => new SelectListItem { Value = a.Id.ToString(), Selected = false, Text = a.Name })
},
NewRoleRolePanelViewModel = newRoleRolePanelViewModel
};
return View("RolePanel", viewModel);
}
var roleStore = new RoleStore<IdentityRole>(new ApplicationDbContext());
var roleManager = new RoleManager<IdentityRole>(roleStore);
await roleManager.CreateAsync(new IdentityRole(newRoleRolePanelViewModel.NewIdentityRole.Name));
return View("RolePanel");
}
[HttpPost]
public ActionResult RemoveRoles(ListRolePanelViewModel listRolePanelViewModel)
{
if (!ModelState.IsValid)
{
var roles = _context.Roles.ToList();
var viewModel = new RolePanelViewModel
{
ListRolePanelViewModel = listRolePanelViewModel,
NewRoleRolePanelViewModel = new NewRoleRolePanelViewModel()
};
viewModel.ListRolePanelViewModel.IdentityRolesSelectListItems = GetSelectListItems(roles,
(a) => new SelectListItem {Value = a.Id.ToString(), Selected = false, Text = a.Name});
return View("RolePanel", viewModel);
}
return View("RolePanel");
}
Custom method that may be needed if you want to run the code
private List<SelectListItem> GetSelectListItems<T>(List<T> dbSetResult, Func<T,SelectListItem> Func)
{
var result = new List<SelectListItem>();
foreach (var item in dbSetResult)
{
result.Add(Func(item));
}
return result;
}

Looping with a Html.CheckBoxFor

I want to produce the below list of typed checkbox
When i inspect each checkbox (eg levelOne) i want to see each having a unique ID and name like the below
I have a Service (ReplayService) that provides a list of objects (HierarchyLevels) which will be used to create the list of Checkboxes
public IEnumerable<HierarchyLevels> GetHierarchyLevels()
{
return new List<HierarchyLevels>()
{
new HierarchyLevels{Name="LevelOne",ShortName="L1", IsSelected = false},
new HierarchyLevels{Name="LevelTwo",ShortName="L2", IsSelected = false},
new HierarchyLevels{Name="TLevelThree",ShortName="L3", IsSelected = false},
new HierarchyLevels{Name="LevelFour",ShortName="L4", IsSelected = false},
};
}
My Controller Class uses the List of HierarchyLevels (created by the service) to create a new Object viewModel.HierarchyLevels (In the Model) of type IEnumerable
public ActionResult Index()
{
var vm = new MyViewModel();
PopulateViewModel(vm.viewModel);
return View(viewModel);
}
private void PopulateViewModel(ContentReplayViewModelBase viewModel)
{
var hierarchyLevels = replayService.GetHierarchyLevels();
viewModel.HierarchyLevels = hierarchyLevels.Select(h => new SelectListItem {Text = h.Name, Selected = h.IsSelected}).ToArray();
}
My Model class has defined properties for each checkbox that will be created.
public abstract class ReplayViewModelBase
{
public IEnumerable<SelectListItem> HierarchyLevels { get; set; }
....
....
}
public class ReplayByHierarchyLevels : ReplayViewModelBase
{
public bool levelOne { get; set; }
public bool leveltwo { get; set; }
public bool levelThree { get; set; }
public bool levelFour { get; set; }
.....
.....
}
In my View i an looping through the list of HierarchyLevels and producing a List of checkbox. the problem I'm having is I'm not sure how to loop through the list of objects and assign a unique bool property in the Model. In the code snippet below I'm assigning bool property "levelOne" to all the created checkbox (as a result all have the same ID and Name)
#foreach (var level in Model.ReplayByHierarchyLevels.HierarchyLevels)
{
<tr>
<td>#level.Text</td>
<td>#Html.CheckBox(level.Text, level.Selected)</td>
<td>** #Html.CheckBoxFor(x => x.ReplayByHierarchyLevels.levelOne, Model.ReplayByHierarchyLevels.levelOne = level.Selected)</td>
</tr>
}
personally, I would just bind to the HierarchyLevels, so the checkbox view will be:
#for(int i =0; i < Model.ReplayByHierarchyLevels.HierarchyLevels.Count; i++)
{
<tr>
<td>#Model.ReplayByHierarchyLevels.HierarchyLevels[i].Text</td>
<td>
#Html.CheckBoxFor(m => m.ReplayByHierarchyLevels.HierarchyLevels[i].Selected)
#Html.HiddenFor(m => m.ReplayByHierarchyLevels.HierarchyLevels[i].Text)
#Html.HiddenFor(m => m.ReplayByHierarchyLevels.HierarchyLevels[i].Value)
</td>
</tr>
}
then if you want strong type of access, you could change the view model ReplayByHierarchyLevels to do:
public class ReplayByHierarchyLevels : ReplayViewModelBase
{
// be aware may be null
public bool levelOne { get{return HierarchyLevels.FirstOrDefault(x => x.Text == "levelOne").Selected;} }
// rest the same
}

Issues in enum values in MVC4

hi all i am try to make a dropdown list using enum values. I have a select field in to my html page like,
<select name="Mem_BloodGr" >
<option value="A+">A+</option><option value="A-">A-</option>
<option value="B+">B+</option><option value="B-">B-</option>
<option value="O+">O+</option><option value="O-">O-</option>
<option value="AB+">AB+</option><option value="AB-">AB-</option>
</select>
This is repeated in many places in my web page. So i am try to generate dropdown list using enum values
namespace .....Models
{
public class MemberData
{
public int Id { get; set; }
public string Mem_NA { get; set; }
........
public BloodGroup Mem_BloodGr { get; set; }
}
public enum BloodGroup
{
A+, //// **error shows here like, "} expected"**
A-,
B-,
B+
}
}
but i got an error when adding enum values . Can anybody please help me.And is that the right way to creating this type dropdown list or any other easy ways in MVC4???
Here is my approach for dropdown for enums:
Make our own attribute:
public class EnumDescription : Attribute
{
public string Text { get; private set; }
public EnumDescription(string text)
{
this.Text = text;
}
}
Make a helper class:
public static class SelectListExt
{
public static SelectList ToSelectList(Type enumType)
{
return ToSelectList(enumType, String.Empty);
}
public static SelectList ToSelectList(Type enumType, string selectedItem)
{
List<SelectListItem> items = new List<SelectListItem>();
foreach (var item in Enum.GetValues(enumType))
{
FieldInfo fi = enumType.GetField(item.ToString());
var attribute = fi.GetCustomAttributes(typeof(EnumDescription), true).FirstOrDefault();
var title = attribute == null ? item.ToString() : ((EnumDescription)attribute).Text;
// uncomment to skip enums without attributes
//if (attribute == null)
// continue;
var listItem = new SelectListItem
{
Value = ((int)item).ToString(),
Text = title,
Selected = selectedItem == ((int)item).ToString()
};
items.Add(listItem);
}
return new SelectList(items, "Value", "Text", selectedItem);
}
}
Enum itself:
public enum DaylightSavingTime
{
[EnumDescription("Detect automatically")]
Auto = 0,
[EnumDescription("DST always on")]
AlwaysOn = 1,
[EnumDescription("DST always off")]
AlwaysOff = 2
}
You can put everything you want in EnumDescription
Usage:
#Html.DropDownList(
"dst",
SelectListExt.ToSelectList(typeof(DaylightSavingTime)),
new {
id = "dst",
data_bind = "value: Dst"
})
Note: data_bind is transformed to "data-bind". It's useful is you use Knockout.js
You can omit the latest new {} block
You can't have + and - in enum values, just letters and numbers. Use APlus or something instead. You could use enums as a source for a dropdown, but I would recommend a list of object that has a name instead. This way you have more control over what is displayed and you are able to use any character in the names. Use something like this to fill the dropdown with:
public class BloodGroup
{
public string Name {get; set; }
// other properties
}
Then you can create a list of BloodGroup-objects that you can reuse in your views:
var BloodGroupList = new List<BloodGroup> { new BloodGroup { Name = "A+"}, new BloodGroup { Name = "A-"}, ... };
And in your views:
#Html.DropDownList("BloodGroups", BloodGroupList.Select(b => new SelectListItem { Name = b.Name, Value = b.Name }))

Submit form with Get method in MVC3?

I have the following form:
#model Teesa.Models.SearchModel
#using (Html.BeginForm("Index", "Search", FormMethod.Get, new { id = "SearchForm" }))
{
<div class="top-menu-search-buttons-div">
#if (!MvcHtmlString.IsNullOrEmpty(Html.ValidationMessageFor(m => m.SearchText)))
{
<style type="text/css">
.top-menu-search-text
{
border: solid 1px red;
}
</style>
}
#Html.TextBoxFor(q => q.SearchText, new { #class = "top-menu-search-text", id = "SearchText", name = "SearchText" })
#Html.HiddenFor(q=>q.Page)
<input type="submit" value="search" class="top-menu-search-submit-button" />
</div>
<div id="top-menu-search-info" class="top-menu-search-info-div">
Please Select one :
<hr style="background-color: #ccc; height: 1px;" />
<div class="top-menu-search-info-checkbox-div">
#Html.CheckBoxFor(q => q.SearchInBooks, new { id = "SearchInBooks", name = "SearchInBooks" })
<label for="SearchInBooks">Books</label>
</div>
<div class="top-menu-search-info-checkbox-div">
#Html.CheckBoxFor(q => q.SearchInAuthors, new { id = "SearchInAuthors" })
<label for="SearchInAuthors">Authors</label>
</div>
<div class="top-menu-search-info-checkbox-div">
#Html.CheckBoxFor(q => q.SearchInTags, new { id = "SearchInTags" })
<label for="SearchInTags">Tags</label>
</div>
}
and the following Controller and Models :
namespace Teesa.Models
{
public class SearchModel
{
[Required(ErrorMessage = "*")]
public string SearchText { get; set; }
public bool SearchInTags { get; set; }
public bool SearchInAuthors { get; set; }
public bool SearchInBooks { get; set; }
public int Page { get; set; }
public List<SearchBookModel> Result { get; set; }
public List<SimilarBookModel> LatestBooks { get; set; }
}
public class SearchBookModel
{
public int Id { get; set; }
public string Title { get; set; }
public string Author { get; set; }
public string Summary { get; set; }
public List<Tags> Tags { get; set; }
public string StatusName { get; set; }
public string SubjectName { get; set; }
public string ThumbnailImagePath { get; set; }
public string BookRate { get; set; }
public string RegistrationDate { get; set; }
public int NumberOfVisit { get; set; }
}
}
[HttpGet]
public ActionResult Index(SearchModel model)
{
FillSearchModel(model);
if (ModelState.IsValid)
{
string page = model.Page;
DatabaseInteract databaseInteract = new DatabaseInteract();
model.Result = new List<SearchBookModel>();
List<Book> allBooks = databaseInteract.GetAllBooks();
List<Book> result = new List<Book>();
#region
if (model.SearchInTags)
{
var temp = (from item in allBooks
from tagItem in item.Tags
where tagItem.Name.Contains(model.SearchText)
select item).ToList();
result.AddRange(temp);
}
if (model.SearchInBooks)
{
var temp = (from item in allBooks
where item.عنوان.Contains(model.SearchText)
select item).ToList();
result.AddRange(temp);
}
if (model.SearchInAuthors)
{
var temp = (from item in allBooks
where item.Author.Contains(model.SearchText)
select item).ToList();
result.AddRange(temp);
}
#endregion
#region Paging
string itemsPerPage = databaseInteract.GetItemsPerPage();
int ItemInPage = int.Parse(itemsPerPage);
var pagingParams = Helpers.SetPagerParameters(page, ItemInPage, result);
ViewBag.AllPagesCount = pagingParams.AllPagesCount;
ViewBag.CurrentPageNumber = pagingParams.CurrentPageNumber;
ViewBag.CountOfAllItems = pagingParams.CountOfAllItems.ToMoneyFormat().ToPersianNumber();
result = pagingParams.ListData as List<Book> ?? result;
#endregion
foreach (var item in result)
{
var bookRate = (item.BookRate == null || item.BookRate.Count == 0)
? 0.0
: item.BookRate.Average(q => q.Rate);
model.Result.Add(new SearchBookModel
{
Author = item.Author,
Id = item.Id,
.
.
.
});
}
}
else
{
model.Result = new List<SearchBookModel>();
}
return View(model);
}
When I submit the form I see the following query strings(Notice the duplicate names) :
http://localhost:2817/Search?SearchText=book&Page=2&SearchInBooks=true&SearchInBooks=false&SearchInAuthors=true&SearchInAuthors=false&SearchInTags=true&SearchInTags=false
But it has to be something like this :
http://localhost:2817/Search?SearchText=book&Page=2&SearchInBooks=true&SearchInAuthors=true&SearchInTags=true
How can I fix it ?
Thanks
Html.Checkbox (and the related For... methods) generate a hidden input for false, and the checkbox for true. This is to ensure that model binding works consistently when binding.
If you must get rid of "false" items resulting from the hidden inputs, you'll need to construct the checkbox inputs yourself (using HTML and not the helper).
<input type="checkbox" id="SearchInBooks" name="SearchInBooks">
Why dont your create a Post Method with a matching name to the Get method. This will ensure that the code is much easier to debug. As you will not have a huge function to go through trying to find problems like this.
I cannot find a where your getting the duplicate url query strings from though.
This will also allow you to bind your results back to the model.
If you want the model binding to happen successfully then you have to go with this way because that is the nature of the Html.CheckBox/Html.CheckBoxFor methods they will render a hidden field as well.
I would suggest rather go with POST to make your life easy. If you still want to use GET then you have to use checkbox elements directly but you have to take care of the model binding issues. Not all the browsers returns "true" when the checkbox is checked for ex. firefox passes "on" so the default model binder throws an error.
Other alternate options is you can go for custom model binder or you can submit the form using jquery by listening to the submit event.

Categories

Resources