How to render multiple checkboxs and radio buttons in view from database - asp.net-mvc

i am new in mvc. the below is a sample of working with multiple check boxes and radio buttons but now i have to generate or inject in my page multiple multiple check boxes and radio buttons as per database. i have two master table called SEX and Hobbies. now i want to show as many as checkboxes as per the records for hobbies in db and the same way i want to show radio buttons for sex.
<form id='your-form' action='#Url.Action("Action","Controller")' method='post'>
<b>Gender</b><br />
<input type='radio' name='gender' value='Male' /> Male <br />
<input type='radio' name='gender' value='Female' /> Female <br />
<hr />
<b>Hobbies</b><br />
<input type='checkbox' name='hobbies' value='Reading' /> Reading <br />
<input type='checkbox' name='hobbies' value='Sports' /> Sports <br />
<input type='checkbox' name='hobbies' value='Movies' /> Movies <br />
<input type='submit' value='Update Profile' />
</form>
i do not know how to achieve it in mvc. do i need to iterate in view html or there is some other way to achieve it. i just want to work with check boxes not checkbox list or radio button list.
also like to know how to capture those value back when user click on submit button after selecting check boxes and radio buttons. if it is done by viewmodel then it would be great.
it will be great help if some one discuss with code sample just to better visualization purpose.
thanks

You need to use a ViewModel and then pass it back e.g.
View Model
public class ViewModel
{
public bool CheckBox1 { get; set; }
public bool CheckBox2 { get; set; }
}
Controller
public ActionResult Index()
{
var model = new ViewModel()
{
CheckBox1 = true,
CheckBox2 = false,
}
return View(model);
}
[HttpPost]
public ActionResult Action(ViewModel model)
{
// model will have your checkbox results
}
View
#model ViewModel
<form id='your-form' action='#Url.Action("Action","Controller")' method='post'>
<b>Gender</b><br />
#Html.RadioButtonFor(x => x.CheckBox1, "Male")
#Html.RadioButtonFor(x => x.CheckBox2, "Female")
<input type='submit' value='Update Profile' />
</form>

I would suggest you to create a model to your view and use Editor Templates.
In this case create a class which will hold the checkbox value and text for the check box say
class HobbyCheckBoxViewItem
{
public string Text {get;set;}
public bool IsChecked {get;set;}
public string HobbyID {get;set;}
}
Model for your main View
class SampleForm
{
public bool Gender {get;set; }
public List<HobbyCheckBoxViewItem> Hobbies {get;set; }
}
Now in your view use #Html.EditorFor(m=>m.Hobbies). For this your need to create EditorTemplates forlder in your view and create template for Hobbies List. Before that have look into EditorTemplates in MVC.
Populate your Hobbies List from the database.
When the user submits the form, your Hobbies List will be automatically populated based on the user selection. Don't forget to put hobby ID in the hidden field in your hobby editor template.

To achieve this easily, you will need a model backing up your view. Assume you have a model with two properties of List<Sex> and List<Hobbies>
This will be
#model Namespace.YourModel
#Html.BeginForm("Action","Controller",FormMethod.Post))
{
<b>Gender</b><br />
#for(int i = 0 ; i < Model.Sex.Count(); i ++)
{
#Html.RadioButton("gender",Model.Sex[i].Name) #Model.Sex[i].Name <br />
}
<hr />
<b>Hobbies</b><br />
#for(int i = 0 ; i < Model.Hobbies.Count();i++)
{
#Html.CheckBoxFor(x=>Hobbies[i].IsChecked) #Hobbies[i].Name
}
<input type='submit' value='Update Profile' />
}
This assumes that your Hobbies model has a 'Name', and IsChecked Property Property, change the name property to what ever your DB list uses,
This particular view Will post to any model that has
Properties of type List<Hobbies> and string Gender.

Related

Create dynamic forms that grow at run time

I'm working in asp.net core inside a MVC application. I'm using the scaffolding feature that creates the views and controller based on a model. Below is the model that i'm using:
class ShoppingList
{
public int ShoppingListId { get; set; }
public string Name { get; set; }
public List<string> ListItems { get; set; }
}
The form that displays to the user via the view only displays the field for Name. I would like the form to be able to show a field for a list item, and then if the user wants to add another list item they can hit a button to add another field to do so. They at run time decide how many shopping list items they want to add.
Here is the razor cshtml form i'm using:
<form asp-action="Create">
<div asp-validation-summary="ModelOnly" class="text-danger"></div>
<div class="form-group">
<label asp-for="Name" class="control-label"></label>
<input asp-for="Name" class="form-control" />
<span asp-validation-for="Name" class="text-danger"></span>
</div>
<div class="form-group">
<input type="submit" value="Create" class="btn btn-default" />
</div>
</form>
Is there an easy way to do this? I don't want to have to hard code a number.
If you want to allow the user to add a new form element on the client side you need to use javascript to update the DOM with the new element you want to add. To list the existing items you may use editor templates. Mixing these 2 will give you a dynamic form. The below is a basic implementation.
To use editor templates, we need to create an editor template for the property type. I would not do that for string type which is more like a generic one. I would create a custom class to represent the list item.
public class Item
{
public string Name { set; get; }
}
public class ShoppingList
{
public int ShoppingListId { get; set; }
public string Name { get; set; }
public List<Item> ListItems { get; set; }
public ShoppingList()
{
this.ListItems=new List<Item>();
}
}
Now, Create a directory called EditorTemplates under ~/Views/YourControllerName or ~/Views/Shared/ and create a view called Item.cshtml which will have the below code
#model YourNameSpaceHere.Item
<input type="text" asp-for="Name" class="items" />
Now in your GET controller, create an object of the ShoppingList and send to the view.
public IActionResult ShoppingList()
{
var vm = new ShoppingList() { };
return View(vm);
}
Now in the main view, All you have to do is call the EditorFor method
#model YourNamespace.ShoppingList
<form asp-action="ShoppingList" method="post">
<input asp-for="Name" class="form-control" />
<div class="form-group" id="item-list">
Add
#Html.EditorFor(f => f.ListItems)
</div>
<input type="submit" value="Create" class="btn btn-default" />
</form>
The markup has an anchor tag for adding new items. So when user clicks on it, we need to add a new input element with the name attribute value in the format ListItems[indexValue].Name
$(function () {
$("#add").click(function (e) {
e.preventDefault();
var i = $(".items").length;
var n = '<input type="text" class="items" name="ListItems[' + i + '].Name" />';
$("#item-list").append(n);
});
});
So when user clicks it adds a new input element with the correct name to the DOM and when you click the submit button model binding will work fine as we have the correct name attribute value for the inputs.
[HttpPost]
public IActionResult ShoppingList(ShoppingList model)
{
//check model.ListItems
// to do : return something
}
If you want to preload some existing items (for edit screen etc), All you have to do is load the ListItems property and the editor template will take care of rendering the input elements for each item with correct name attribute value.
public IActionResult ShoppingList()
{
var vm = new ShoppingList();
vm.ListItems = new List<Item>() { new Item { Name = "apple" } }
return View(vm);
}
First this is you must have a public accessor to your ShoppingList class.
So, public class ShoppingList.
Next is your view will need the following changes.
#model ShoppingList
<h1>#Model.Name</h1>
<h2>#Model.ShoppingListId</h2>
foreach(var item in Model.ListItems)
{
<h3>#item</h3>
}
So, the above code is roughly what you are looking for.
In Razor you can accessor the models variables by using the #model at the top of the view. But one thing you need to note is if your model is in a subfolder you'll need to dot into that.
Here's an example: #model BethanysPieShop.Models.ShoppingCart.
Here BethanysPieShop is my project name, Models is my folder the ShoppingCart class is in.

Get Values of DropDownList which is inside webgrid and also each dropdown is an attribute of the model

I have a webgrid contains a dropdown which contains different items for each user(Items are grouped). I want to get the selected values to the controller . How can I do that. Heres my ;
Model :
public SelectList AvailableDevices { get; set; }
View :
...
var grid = new WebGrid(Model. ...
..
..
grid.Column(header: "AvailableDevices", format: #item => Html.DropDownList("value", (IEnumerable<SelectListItem>)item.AvailableDevices)),
And I have a Submit Button
#using (Html.BeginForm("AssignUserDevices", "Device"))
{
<input type="submit" value="setUserDevice" onchange="CheckSelectedDevices()" />
}
I want to set users device according to his user type. I know what his choices and send dropdown items according to his type. So each item in webgrid differs from each other.
And Also I dont know how to give indices to each item in webgrid.( I think we will need it.)
Im new at MVC so hope you will understand.
Thanks;
What I got from our requirement that you want the selected item and have that item value in form field before posting if yes then you can follow as given.
#Html.DropDownList("value", (IEnumerable<selectlistitem>)item.AvailableDevices), new {#class="deviceclass"} )
#using (Html.BeginForm("AssignUserDevices", "Device"))
{
<input type="hidden" value="" name="deviceId" id="deviceId" />
<input type="hidden" value="" name="userId" />
<input type="submit" value="setUserDevice" />
}
<script>
$(".deviceclass").on('change', function () {
var dropdownvalue = $(this).val();
$('#deviceId').val(dropdownvalue);
})
</script>
and you can define an action function in controller
public ActionResult Details(string deviceId, string userId)
{
// do as you need.
return View();
}

How To Pass Value Entered In A Text Box To An Action Method

I was building a Movies application using MVC. CRUD was automatically created for me by Visual Studio. Now, I am trying to build a Search functionality for the user. Here is the code I wrote:
#using (Html.BeginForm("SearchIndex", "Movies", new {searchString = ??? }))
{
<fieldset>
<legend>Search</legend>
<label>Title</label>
<input type ="text" id="srchTitle" />
<br /><br />
<input type ="submit" value="Search" />
</fieldset>
}
I have built the SearchIndex method and the associated view. I just can't find how to pass the value entered in the text box to the SearchIndex action method.
Please help.
In your Model:
public class Search
{
public String SearchText { get; set; }
}
Make your View strongly typed and use
#Html.EditorFor(model => model.SearchText)
In your Controller:
[HttpPost]
public ActionResult SearchIndex(Search model)
{
String text = model.SearchText;
}
Hope this helps.
You need to give your input field a name:
<input type="text" id="srchTitle" name="movieToFind" />
Then in your Controller make sure it has a string parameter:
in MoviesController:
[System.Web.Mvc.HttpPost]
public ActionResult SearchIndex(string movieToFind)
{
//Controller Action things.
}
Note: Form fields names must match the parameters expected in the controller. Or map to model properties if a 'Model' is expected.

How to create an EditorFor a collection and avoid doing a loop

For example:
Model
public class Person
{
public int ID { get; set; }
public string FirstName { get; set; }
public string LastName { get; set; }
}
Editor Template for Person (PersonEditor.cshtml):
#model MvcApplication1.Models.Person
#Html.HiddenFor(x=>x.ID)
<label>First Name</label>
#Html.TextBoxFor(x=>x.FirstName)
<label>Last Name</label>
#Html.TextBoxFor(x=>x.LastName)
<br />
On my main page, I want to be able to do the following:
#model IList<MvcApplication1.Models.Person>
#using (Html.BeginForm())
{
#Html.EditorFor(x=>x,"PersonEditor")
}
And have all the elements in the form, generate the proper names automatically; instead of having to loop through the collection as I am doing now:
#using (Html.BeginForm())
{
for (int i = 0; i < Model.Count; i++)
{
#Html.EditorFor(x=>Model[i],"PersonEditor")
}
}
The form elements must contain the following format:
<input name="[0].ID" type="text" value="Some ID" />
<input name="[0].FirstName" type="text" value="Some value" />
<input name="[1].ID" type="text" value="Some x" />
<input name="[1].FirstName" type="text" value="Some y" />
And so on...
Because in my controller, I expect to receive an IList<Person> when the form posts pack.
Can I eliminate that for loop completely?
EDIT
Right now, when I simply do #Html.EditorFor(x=>x) (without the loop, in other words), I get this exception:
The model item passed into the dictionary is of type
'MvcApplication1.Models.Person[]', but this dictionary requires a
model item of type 'MvcApplication1.Models.Person'.
You should be able to use the same template for both IEnumerable<T> and T. The Templating is smart enough to enumerate the IEnumerable, but you will need to rename the editor template to match the type name. Then you should be able to use
#model IList<MvcApplication1.Models.Person>
#using (Html.BeginForm())
{
#Html.EditorForModel()
}
Unfortunately, it looks like a template named anything other than the type name will throw an exception
The model item passed into the dictionary is of type
'MvcApplication1.Models.Person[]', but this dictionary requires a
model item of type 'MvcApplication1.Models.Person'

ViewData not being posted back to Controller

I have two pages, one that edits user information, and one that edits information in a pictures table. I recently stopped using strongly typed viewmodels due to the varying types of data required on each page.
The page that edits the user information works fine, but the page that edits picture information does not post back any of the edits that are made in the input fields; except for the ID, which is correct, all the other values come back as null. They both seem to be structured exactly the same way -- I can't figure out what's the difference. As far as I can tell the code for both pages are the same, but I'm not getting data back on the second one.
User Controller and View which works
Controller
public ActionResult Preferences()
{
int userid = getUserID(User.Identity.Name);
// Info for user preferences
var accountInfo = db.users.Single(l => l.ID == userid);
ViewData["accountInfo"] = accountInfo;
AccountController usr = new AccountController(); // Info for user menu
ViewData["userInfo"] = usr.getUserInfo(User.Identity.Name);
return View();
}
[HttpPost]
public ActionResult Preferences(user accountInfo, string oldPW)
{
// Do stuff to save user info
return RedirectToAction(actionname, routeValues);
}
View
#using (Html.BeginForm("Preferences", null, FormMethod.Post,
new { id = "prefsform" }))
{
AutoShowApp_MVC.user item = new AutoShowApp_MVC.user();
item = ViewBag.accountInfo;
<input id="lastname" name="lastname" type="text" value="#item.lastname"/>
<input id="address1" name="address1" type="text" value="#item.address1"/>
<input id="city" name="city" type="text" value="#item.city"/>
<input id="state" name="state" type="text" value="#item.state"/>
<input type="submit" value="Submit Changes" />
}
Picture Controller and View which DON'T work
Controller:
public ActionResult Edit(long id)
{
var picInfo = db.lmit_pics.Single(l => l.ID == id);
ViewData["picInfo"] = picInfo; // get Picture Info
// Get User Info for menu
AccountController usr = new AccountController();
ViewData["userInfo"] = usr.getUserInfo(User.Identity.Name);
return View();
}
[HttpPost]
public ActionResult Edit(lmit_pics picInfo)
{
// Do stuff to save picInfo
return RedirectToAction("Index");
}
View:
#using (Html.BeginForm("Edit", null, FormMethod.Post, new { id = "editform" }))
{
AutoShowApp_MVC.lmit_pics item = new AutoShowApp_MVC.lmit_pics();
item = ViewBag.picInfo;
<input type="text" id="model" value="#item.model" />
<input type="text" id="description" value="#item.description" />
<input type="submit" value="Save" />
}
You do not have the name attribute specified on the inputs on your picture editing form.
<input type="text" id="model" value="#item.model" />
Should Be
<input type="text" id="model" name="model" value="#item.model" />
The form collection works from the name attribute, not the Id attribute which is why you are not getting any data back (you are, it is just not properly attributed).
However, I agree with Wahid above, using strongly typed view models, editorFor helpers, etc not only help to prevent issues such as the above, but really go a long way in making a more secure, easier to maintain site.

Resources