How to collect data from an unlimited number of items RadioButton? - asp.net-mvc

#{int i=0;}
#foreach (var e in Model.BlockList)
{
#foreach (var e2 in e.RadioButtons)
{
<label>#Html.RadioButton("r"+i, e2.Id, false) #e2.ViewText</label><br />
}
i++;
}
Question: how in the controller through all the answers?
At this moment my Controller class look like this:
[HttpPost]
public ActionResult Index(DocAlpha a)
{
List<int> results = new List<int>();
int i = 0;
while (Request.Params["r" + i.ToString()] != null)
{
int val = 0;
if(int.TryParse(Request.Params.Get("r" + i.ToString()), out val))
{
results.Add(val);
}
i++;
}
return Index();
}
may be better ways?

You can make an array of radio buttons names like so (note the names):
Html :
<input type="text" name="r[0]" value="" />
<input type="text" name="r[1]" value="" />
<input type="text" name="r[2]" value="" />
<!--and so on -->
Then make your action accept an array:
public ActionResult TheAction (string[] r) {
}
The default model binder will automatically populate the answers array in your action with the values entered in the form.

Related

How to get MVC button to populate and display a table after being clicked

I've looked for 4 or 5 hours now on how to get this to work but I simply cannot figure it out. I'm suppose to get a form that has both a submit and delete button. The submit should submit the data in the form to a table that gets populated and created at the same time while the delete button would delete the most recent addition. It doesn't seem to matter what I've tried to do it just doesn't work. Whenever I click on my save button it just reloads the page with empty form fields and no table with the data.
My Controller code
public class PersonController : Controller
{
private static List<Person> Persons = new List<Person>();
public ActionResult Index()
{
return View();
}
public ActionResult Start()
{
return View("PersonData");
}
public ActionResult AddPerson(string firstName, string lastName, string birthDate)
{
Person p = new Person();
p.firstName = firstName;
p.lastName = lastName;
p.birthDate = birthDate;
if (Persons.Count > 0)
{
Persons.Add(p);
}
return View("PersonData");
}
public ViewResult DeletePerson()
{
if(Persons.Count > 0)
{
Persons.RemoveAt(0);
}
return View("PersonData");
}
}
My View code
#model IEnumerable<UsingViewsandModels.Models.Person>
....
#using (Html.BeginForm("AddPerson", "PersonController"))
{
}
<form>
<label name="firstName">First Name: </label>
<input type="text" name="firstName" />
<br />
<label name="lastName">Last Name: </label>
<input type="text" name="lastName" />
<br />
<label name="birthDate">Birth Date: </label>
<input type="text" name="birthDate" />
<br />
<button type="submit" value="Submit" name="AddPerson" onclick="AddPerson()">Save</button>
<button type="submit" value="Delete" name="DeletePerson" onclick="DeletePerson()">Delete</button>
</form>
#if (Model != null && Model.Count() > 0)
{
<table>
<tr><th>FirstName</th><th>LastName</th><th>BirthDate</th></tr>
#foreach (UsingViewsandModels.Models.Person p in Model)
{
<tr>
<td>p.firstName)</td>
<td>p.lastName)</td>
<td>p.birthDate)</td>
</tr>
}
</table>
}
Any help would be greatly appreciated. I'm fairly certain I'm just being an idiot and it's something very simple.
You have this code:
return View("PersonData");
That means: return the view named "PersonData".
You are not sending no data to the view. Use the overload and send the model to your view like this:
return View("PersonData", Persons);
Now your view has access to all the data in Persons and it will work.

Dynamically adding controls in MVC4

I am currently working on creating an MVC4 application where I want controls to be generated automatically from the database rows.
I have the table in my database containing the questions and the control type in which it should be answered by the user.
I am just thinking of a logic like
Where I can get the database rows in a dataset and then foreach it, then checking the type of control it belongs and then creating the control in my View.
This is my Controller action:
Public ActionResult Index()
{
// get the rows from the table
foreach(Iterate the rows)
{
if(controllerType1)
{
//stmnts
}
if(controllerType2)
{
//stmnts
}
}
return View();
}
This is just an idea of how can we build the solution. If I am going in the right way please guide me, else I am eager to know the possibilities where I can build my solution in different ways :).
You can create a editor template and pass the control list as model to the template and in the template you can iterate that list to generate the control. As i have shown below.
1->Create a class for Control Information.
public class ControlInfo
{
public string ControlType { get; set; }
public string ControlID { get; set; }
public string ControlName { get; set; }
public string ControlValue { get; set; }
public string ControlLabel { get; set; }
public bool IsChecked { get; set; }
}
2->Create an Editor Template (Partial view with control name say CustomControl.cshtml) in \Views\Shared\EditorTemplates path.
#model List<MvcApplication2.Models.ControlInfo>
<table>
#foreach (MvcApplication2.Models.ControlInfo ControlInfo in Model)
{
<tr>
<td>#ControlInfo.ControlLabel</td>
<td>
#switch (ControlInfo.ControlType.ToLower())
{
case "textbox":
<input type="text" name="#ControlInfo.ControlName" id="#ControlInfo.ControlID" value="#ControlInfo.ControlValue" />
break;
case "checkbox":
if (ControlInfo.IsChecked)
{
<input type="checkbox" name="#ControlInfo.ControlName" id="#ControlInfo.ControlID" value="#ControlInfo.ControlValue" checked="checked" />
}
else
{
<input type="checkbox" name="#ControlInfo.ControlName" id="#ControlInfo.ControlID" value="#ControlInfo.ControlValue" checked="checked" />
}
break;
default:
break;
}
</td>
</tr>
}
</table>
3->Create a model for main view (say HomeModel).
public class HomeModel
{
public List<ControlInfo> ControlList { get; set; }
public void PolulateControlList()
{
//You can fill this list from database.
// For example i have filled the list manually.
ControlList = new List<ControlInfo>();
ControlList.Add(new ControlInfo() {ControlType="TextBox",ControlName="tbox1", ControlID="tbox1", ControlLabel="Name", ControlValue="Martin" });
ControlList.Add(new ControlInfo() { ControlType = "CheckBox", ControlName = "cbox1", ControlID = "cbox1", ControlLabel="Is Correct", ControlValue = "Yes", IsChecked=true });
}
}
4->Consume the editor template in the main view as.
#model MvcApplication2.Models.HomeModel
#{
ViewBag.Title = "Home Page";
}
#Html.EditorFor(model=>model.ControlList,"CustomControl")
5-> Call the main view in the controller ( Index here).
public ActionResult Index()
{
HomeModel ModelObj = new HomeModel();
ModelObj.PolulateControlList();
return View(ModelObj);
}
Edit 1:
For getting the posted value you need to modify the Editor Templates as below. The model properties whose name is equal to the name of the control posted as name value collection , will get automatically binded by the model binder of the mvc frame work, so for each property in the control collection i have created hidden tags and one input tag for the input value.
#model List<MvcApplication2.Models.ControlInfo>
<table>
#{ var index = -1;}
#foreach (MvcApplication2.Models.ControlInfo ControlInfo in Model)
{
index++;
<tr>
<td>#ControlInfo.ControlLabel</td>
<td>
<input type="hidden" name="#("ControlList[" + index + "].ControlID")" value="#ControlInfo.ControlID" />
<input type="hidden" name="#("ControlList[" + index + "].ControlLabel")" value="#ControlInfo.ControlLabel" />
<input type="hidden" name="#("ControlList[" + index + "].ControlName")" value="#ControlInfo.ControlName" />
<input type="hidden" name="#("ControlList[" + index + "].ControlType")" value="#ControlInfo.ControlType" />
#switch (ControlInfo.ControlType.ToLower())
{
case "textbox":
<input type="text" name="#("ControlList["+index+"].ControlValue")" id="#ControlInfo.ControlID" value="#ControlInfo.ControlValue" />
break;
case "checkbox":
<input type="hidden" name="#("ControlList[" + index + "].ControlValue")" value="#ControlInfo.ControlValue" />
if (ControlInfo.IsChecked)
{
<input type="checkbox" name="#("ControlList[" + index + "].IsChecked")" id="#ControlInfo.ControlID" value="true" checked="checked" />
}
else
{
<input type="checkbox" name="#("ControlList[" + index + "].IsChecked")" id="#ControlInfo.ControlID" value="true" />
}
break;
default:
break;
}
</td>
</tr>
}
</table>
And in the main view you need to have form
#model MvcApplication2.Models.HomeModel
#{
ViewBag.Title = "Home Page";
}
#using(Html.BeginForm()){
#Html.EditorFor(model=>model.ControlList,"CustomControl")
<input type="submit" name="name" value="Submit" />
}
And in controller you need to have corresponding post method
[HttpPost]
public ActionResult Index(HomeModel ModelObj)
{
// Your logic..........
return View(ModelObj);
}
This ModelObj will have the posted values.

Passing Values from the SelectList Items Using ViewModel

I'd like to get the values of the selected items in dropdownlists. I am saving the files into the database with the following code:
public ActionResult UploadDoc(IEnumerable<HttpPostedFileBase> files)
{
foreach (var file in files)
{
if (file != null && file.ContentLength > 0)
{
byte[] data = new byte[file.ContentLength];
file.InputStream.Read(data, 0, file.ContentLength);
Document doc = new Document
{
UploadedOn = DateTime.Now,
MimeType = file.ContentType,
UserName = User.Identity.Name,
Data = data,
FromLanguage = 1,
ToLanguage = 2
};
dbContext = new MedicalDb();
dbContext.Documents.Add(doc);
dbContext.SaveChanges();
}
}
return RedirectToAction("Index");
}
but, I'd also like to get the selected values from the dropdownlists so that I can populate the FromLanguage and ToLanguage properties of the documents. I guess I'd need a viewmodel, but don't know how to do it. New rows for document upload are added using jQuery and names of the ddls are "ddlFromLanguage1", "ddlFromLanguage2", "ddFromLanguage3", and "ddlToLanguage1", "ddlToLanguage2", "ddlToLanguage3", etc. Thanks in advance for any help.
<form action="UploadDoc" method="post" enctype="multipart/form-data">
<table id="tblUploadDocs">
<tr id="row1">
<td><input type="file" name="files" id="file1" /></td>
<td>Bu dilden</td>
<td>#Html.DropDownList("ddlFromLanguage1", ViewBag.Languages as SelectList)</td>
<td>şu dile çevrilecek</td>
<td>#Html.DropDownList("ddlToLanguage1", ViewBag.Languages as SelectList)</td>
</tr>
</table>
<br />
Yeni dosya ekleyin
<input type="submit" />
</form>
Any form that is posted back returns a FormCollection to the controller in addition to model related values.
For example
//In your view
#using (Html.BeginForm("CountrySelect", "Country", FormMethod.Post))
{
#Html.AntiForgeryToken()
<select name="country" id="country-select">
<option value="selector">Pick a Country</option>
<option value="England">England</option>
<option value="England">England</option>
</select>
}
//In controller
//This will get you the name of the selected country from your form
[HttpPost]
Public ActionResult CountrySelect(FormCollection formData)
{
string country = formData["country"].toString();
}
I think you need to look at good example and do the same or very similar to them.
Take a look at these:
ASP.NET MVC 3 Viewmodel Pattern
Implementing Dropdownlist on Asp.net MVC 3 from viewModel
These should get you going.
Please let me know if you don't succeed or if what I gave you was actually helpful.
Thanks
The solution:
The viewmodel:
public class CustomerDocUploadViewModel
{
public HttpPostedFileBase File { get; set; }
public int FromLanguage { get; set; }
public int ToLanguage { get; set; }
}
The view:
#model IList<Models.ViewModels.CustomerDocUploadViewModel>
...
<form action="UploadDoc" method="post" enctype="multipart/form-data">
<table id="tblUploadDocs">
<tr id="row1">
<td><input type="file" name="[0].File" /></td>
<td>Bu dilden</td>
<td>#Html.DropDownList("[0].FromLanguage", ViewBag.Languages as SelectList)</td>
<td>şu dile çevrilecek</td>
<td>#Html.DropDownList("[0].ToLanguage", ViewBag.Languages as SelectList)</td>
</tr>
</table>
<br />
<a id="lnkAdd" href="javascript:addRow();" style="margin:10px 0;">Yeni dosya ekleyin</a>
<input type="submit" />
</form>
and finally the action method in the controller:
[HttpPost]
public ActionResult UploadDoc(IList<CustomerDocUploadViewModel> docInfos)
{
for (int i = 0; i < docInfos.Count; i++)
{
if (docInfos.ElementAt(i).File != null && docInfos.ElementAt(i).File.ContentLength > 0)
{
byte[] data = new byte[docInfos.ElementAt(i).File.ContentLength];
docInfos.ElementAt(i).File.InputStream.Read(data, 0, docInfos.ElementAt(i).File.ContentLength);
// Save the file into the database
Document doc = new Document
{
UploadedOn = DateTime.Now,
MimeType = docInfos.ElementAt(i).File.ContentType,
UserName = User.Identity.Name,
Data = data,
FromLanguage = docInfos.ElementAt(i).FromLanguage,
ToLanguage = docInfos.ElementAt(i).ToLanguage
};
dbContext = new MedicalDb();
dbContext.Documents.Add(doc);
dbContext.SaveChanges();
}
}
return RedirectToAction("Index");
}

ASP.Net MVC 3 Dictionary Binding

Hello I have a model object defined in an MVC 3 project that has a Dictionary property as follows:
MyObj.ObjDictionary<string,string>
I have two controller methods, one which handles returning the view and another that handles the POSTed form from the view
public ActionResult Scanner(string val_1, string val_2, string val_3)
{
//Fetch sessionObj from Model
MyObj sessionObj = getSessionObj(val_1, val_2, val_3);
//At this point model.ObjDictionary<string,string> contains data
return View(sessionObj);
}
[HttpParamAction]
[AcceptVerbs(HttpVerbs.Post)]
public ActionResult Scanner(MyObj model)
{
//At this point model.ObjDictionary<string,string> is null
//i.e. binding is not being properly achieved
//Validate POSTed data
}
In the View, I iterate through each key-value pair (kvp). It has to be done this way since the property is dynamic and I have no way of knowing how many dictionary values there will be.
#using (Html.BeginForm("Action", "Home"))
{
#foreach (var kvp in Model.ObjDictionary)
{
<span>#Html.Label("Scan " + #kvp.Key)</span>
<span>#Html.TextBox(kvp.Key, "", new { #style = "font-size:Medium;width:400px;" })</span>
}
<input type="submit" name="Cancel" value="Cancel" />
<input type="submit" id="Scanner" name="Scanner" value="Scanner" />
}
The goal is to provide a way for users to input data and have that data bound to the values of the specific key. My problem is that the Model.ObjDictionary is null when it gets POSTed. I'm not sure what I'm doing wrong, I read over this article, but this assumes pre-existing values in a dictionary. Is there a way the ModelBinder can bind the data, entered by a user, to a dictionary value mapped to a specific key?
The article you referenced answers your question, you simply need to provide the correct names for your controls, try:
#using (Html.BeginForm("Action", "Home")) {
var i = 0;
foreach (var kvp in Model.ObjDictionary)
{
#Html.Hidden("ObjDictionary[" + i + "].Key", kvp.Key)#kvp.Key
<span>#Html.TextBox("ObjDictionary[" + i + "].Value", kvp.Value, new { #style = "font-size:Medium;width:400px;" })</span>
i++;
<br />
}
<input type="submit" value="Submit" />
}
For dictionaries, each entry should have one field for the key and one field for the value.
#using (Html.BeginForm("Action", "Home"))
{
var index = 0;
#foreach (var kvp in Model.ObjDictionary)
{
<span>#Html.Hidden("ObjDictionary[" + index + "].Key", kvp.Key)
<span>#Html.Label("Scan " + #kvp.Key)</span>
<span>#Html.TextBox("ObjDictionary[" + index + "].Value", kvp.Value, new { #style = "font-size:Medium;width:400px;" })</span>
index++;
}
<input type="submit" name="Cancel" value="Cancel" />
<input type="submit" id="Scanner" name="Scanner" value="Scanner" />
}
By the way, I have encapsulated this functionality in an HTML helper class. You can find it and a working demonstration here: https://github.com/ErikSchierboom/aspnetmvcdictionaryserialization

CheckboxFor not binding with nested objects

CheckBoxFor is not bounded when a property is defined in an object nested in the model?
Here is an example. I have a SearchOptions model that contains a List<Star> property. Each Star has a number, a name and a bool property that should be bounded:
public class SearchOptions
{
public SearchOptions()
{
// Default values
Stars = new List<Star>()
{
new Star() {Number=1, Name=Resources.Home.Index.Star1,
IsSelected=false},
new Star() {Number=2, Name=Resources.Home.Index.Star2,
IsSelected=false},
new Star() {Number=3, Name=Resources.Home.Index.Star3,
IsSelected=true},
new Star() {Number=4, Name=Resources.Home.Index.Star4,
IsSelected=true},
new Star() {Number=5, Name=Resources.Home.Index.Star5,
IsSelected=true},
};
}
public List<Star> Stars { get; set; }
}
In my strongly typed View (of SearchOptions) i loop over Stars property:
#using (Html.BeginForm("Do", "Home"))
{
<fieldset>
<legend>#MVC3TestApplication.Resources.Home.Index.Search</legend>
#{
foreach (Star s in Model.Stars)
{
#Html.CheckBoxFor(m => s.IsSelected)
<label>#s.Name</label>
}}
</fieldset>
<input type=submit value="Invia" />
}
The (relevant part of) controller is:
public ActionResult SearchOptions()
{
return View(new SearchOptions());
}
[HttpPost]
public ActionResult Do(SearchOptions s)
{
// Do some stuff
return View("SearchOptions", s);
}
It's because of how you're accessing the properties in the CheckBoxFor expression.
#for (int i = 0; i < Model.Stars.Count(); i++) {
#Html.CheckBoxFor(m => m.Stars[i].IsSelected)
<label>#Model.Stars[i].Name</label>
}
This should work for you.
Here's the output from the different methods:
//using the for loop
<input id="Stars_2__IsSelected" name="Stars[2].IsSelected" type="checkbox" value="true" />
//using the foreach
<input checked="checked" id="s_IsSelected" name="s.IsSelected" type="checkbox" value="true" />
You'll notice that the for foreach doesn't contain the proper name for it to match to when doing model binding.

Resources