Filling in the SelectList with a for loop - asp.net-mvc-4

Ok, my drop down used to be made like so:
<select id="Level" onchange="showChoice(this.value);">
<option id="0" value="0">Pick a Level</option>
#for (int i =1; i <= Model.ExamplesCount; i++ )
{
<option id="#i" value="#i">Level #i</option>
}
</select>
because the ExamplesCount number changes per user. But I need to use the Html.ValidationMessageFor() thing, which I can't get to work with this.
I need one of two solutions.
Can I make Html.ValidationMessageFor() work with this select tag?
or if not,
2.Can I use Html.DropDownListFor() but fill it in with a similar for loop?
For example,
#Html.DropDownListFor(
m => m.Level,
new SelectList(
new List<Object> {
new {value = 0, text ="Pick a Level"},
new { value = 1, text = "Level 1"},
new { value = 2, text = "Level 2" },
new { value = 3, text = "Level 3" },
new { value = 4, text = "Level 4" },
new { value = 5, text = "Level 5" }
},
"value", "text", null))
#Html.ValidationMessageFor(model => model.Level)
The above code works, but where I am hard coding all the SelectList values, I'd like to have an for loop that does it for me.

What about creating a object in your model that will content all the items you want an then pass that to your view? Example:
In your Model.
public class Model{
...other properties
public List<ListItemSource> myLevels { get; set; }
[Required(ErrorMessage = #"*Required")]
public string Level { get; set; }
}
In your controller:
public ActionResult YourAction(Model myModel)
{
var myModel = new Model
{
myLevels =methodToGetLevels()
};
return view(myModel);
}
In your View:
#Html.DropDownListFor(x => x.Level,
new SelectList(Model.myLevels, "Value", "Text"))
#Html.ValidationMessageFor(model => model.Level)
Where x.Level will hold the selected value and Model.myLevels is the collection of levels.
I hope this help to solve your problem.

Related

RadioButton list Binding in MVC4

I have a radiobuttonList which is binding data from Enum Class and its working correctly in the view.
But my concern is how can I set inital value of radiobutton to CROCount.ONE.I have tried to set the initial value in the following way but couldnot get the desired result.
public enum CROCount
{
ONE = 1,
TWO = 2
}
ViewModel is
public class RegistraionVM
{
....
public EnumClass.CROCount CROCount { get; set; }
}
I generated the radio button list as follows.
<div>
#foreach (var count in Enum.GetValues(typeof(SMS.Models.EnumClass.CROCount)))
{
<label style="width:75px">
#Html.RadioButtonFor(m => m.RegistrationVenue, (int)count,
new { #class = "minimal single" })
#count.ToString()
</label>
}
</div>
Binding performed in the Controller is
public ActionResult Index(int walkInnId)
{
try
{
var _studentReg = new RegistraionVM
{
CROCount=EnumClass.CROCount.ONE
};
return View(_studentReg);
}
catch (Exception ex)
{
return View("Error");
}
}
Your binding your radio button to property CROCount (not RegistrationVenue) so your code should be
#Html.RadioButtonFor(m => m.CROCount, count, new { id = "", #class = "minimal single" })
Note that the 2nd parameter is count (not (int)count) so that you generate value="ONE" and value="TWO". Note also the new { id = "", removes the id attribute which would otherwise result in duplicate id attributes which is invalid html.

MVC4 ViewData.TemplateInfo.HtmlFieldPrefix generates an extra dot

I'm trying to get name of input correct so a collection of objects on my view model can get bound.
#{ViewData.TemplateInfo.HtmlFieldPrefix = listName;}
#Html.EditorFor(m => m, "DoubleTemplate", new {
Name = listName,
Index = i,
Switcher = (YearOfProgram >= i +1)
})
As you can see here, I pass in the "listName" as the prefix for my template, the value of listName = "MyItems".
And here is my template:
#model Web.Models.ListElement
#if (ViewData["Switcher"] != null)
{
var IsVisible = (bool)ViewData["Switcher"];
var index = (int)ViewData["Index"];
var thisName = (string)ViewData["Name"] + "[" + index + "].Value";
var thisId = (string)ViewData["Name"] + "_" + index + "__Value";
if (IsVisible)
{
#*<input type="text" value="#Model.Value" name="#thisName" id ="#thisId" class="cell#(index + 1)"/>*#
#Html.TextBoxFor(m => m.Value, new { #class ="cell" + (index + 1)})
#Html.ValidationMessageFor(m => m.Value)
}
}
but I found that the generated name becomes this: MyItems.[0].Value
It has one extra dot. How can I get rid of it?
Incidentally, I tried to manually specify the name inside the template and found the name gets overridden by the Html helper.
Update
The reason why I have to manually set the HtmlFieldPrefix is the property name (MyItems which is a list of objects) will get lost when MyItems is passed from main view to the partial view. By the time, the partial view called my template and passed in one object in MyItems, the template itself has no way to figure out the name of MyItems as it has been lost since the last "pass-in".
So that's why I have to manually set the html field prefix name. And I even tried to use something similar to reflection(but not reelection, I forgot the name) to check the name of passed in object and found it returned "Model".
Update 2
I tried Stephen's approach, and cannot find the html helper PartialFor().
I even tried to use this in my main view:
Html.Partial(Model, "_MyPartialView");
In Partial View:
#model MvcApplication1.Models.MyModel
<h2>My Partial View</h2>
#Html.EditorFor(m => m.MyProperty)
Here is my templat:
#model MvcApplication1.Models.ListElement
#Html.TextBoxFor(m => m.Value)
Here is my Model:
public class MyModel
{
private List<ListElement> myProperty;
public List<ListElement> MyProperty
{
get
{
if (myProperty == null)
{
this.myProperty = new List<ListElement>() { new ListElement() { Value = 12 }, new ListElement() { Value = 13 }, new ListElement() { Value = 14 }, new ListElement() { Value = 15 }, };
}
return this.myProperty;
}
set
{
this.myProperty = value;
}
}
}
public class ListElement
{
[Range(0, 999)]
public double Value { get; set; }
}
And here is my controller:
public ActionResult MyAction()
{
return View(new MyModel());
}
It only generates raw text("12131415") for me, instead of the wanted text box filled in with 12 13 14 15.
But if I specified the template name, it then throws an exception saying:
The template view expecting ListElement, and cannot convert
List<ListElement> into ListElement.
There is no need set the HtmlFieldPrefix value. MVC will correctly name the elements if you use an EditorTemplate based on the property type (and without the template name).
Assumed models
public class ListElement
{
public string Value { get; set; }
....
}
public class MyViewModel
{
public IEnumerable<ListElement> MyItems { get; set; }
....
}
Editor template (ListElement.cshtml)
#model YourAssembly.ListElement
#Html.TextBoxFor(m => m.Value)
Main view
#model YourAssembly.MyViewModel
...
#Html.EditorFor(m => m.MyItems) // note do not specify the template name
This will render
<input type="text" name="MyItems[0].Value" ...>
<input type="text" name="MyItems[1].Value" ...>
....
If you want to do this using a partial, you just can pass the whole model to the partial
MyPartial.cshtml
#model #model YourAssembly.MyViewModel
#Html.EditorFor(m => m.MyItems)
and in the main view
#Html.Partial("MyPartial")
or create an extension method
public static MvcHtmlString PartialFor<TModel, TProperty>(this HtmlHelper<TModel> helper,
Expression<Func<TModel, TProperty>> expression, string partialViewName)
{
string name = ExpressionHelper.GetExpressionText(expression);
object model = ModelMetadata.FromLambdaExpression(expression, helper.ViewData).Model;
var viewData = new ViewDataDictionary(helper.ViewData)
{
TemplateInfo = new System.Web.Mvc.TemplateInfo { HtmlFieldPrefix = name }
};
return helper.Partial(partialViewName, model, viewData);
}
}
and use as
#Html.PartialFor(m => m.MyItems, "MyPartial")
and in the partial
#model IEnumerable<YourAssembly.ListElement>
#Html.EditorFor(m => m)
Call your partial this way:
#Html.Partial("_SeatTypePrices", Model.SeatTypePrices, new ViewDataDictionary
{
TemplateInfo = new TemplateInfo() {HtmlFieldPrefix = nameof(Model.SeatTypePrices)}
})
Partial view:
#model List
#Html.EditorForModel()
Editor template implementation:
#using Cinema.Web.Helpers
#model Cinema.DataAccess.SectorTypePrice
#Html.TextBoxFor(x => Model.Price)
This way your partial view will contain list of items with prefixes.
And then call EditorForModel() from your EditorTemplates folder.
I found that I can change the value of HtmlFeildPrefix in my template.
So what I did to solve my problem was just to assign the correct value to HtmlFeildPrefix in the template directly rather than in the page which calls the template.
I hope it helps.
If I want to pass the HtmlFieldPrefix I use the following construct:
<div id="_indexmeetpunttoewijzingen">
#Html.EditorFor(model => model.MyItems, new ViewDataDictionary()
{
TemplateInfo = new TemplateInfo()
{
HtmlFieldPrefix = "MyItems"
}
})
</div>

how to set the selected value in the drop down list populated with ViewData in mvc

I am new to MVC, please help me to set the selected value in drop down list populated using View Data. I have gone through so many solutions but every solutions deals with selecting value for single drop down. I have same drop down listed using the foreach loop. Setting selected value for each dropdown in that foreach loop.
My code is shown below.
[In view]
int i = 0;
foreach (var item in Model.Select((x, j) => new { Data = x, Index = j + 1 })) {
#Html.DropDownListFor(model => item.Data.CategoryID,(IEnumerable<SelectListItem>)ViewData["categories"], new { #id = "category" + i })
i++;
}
[in controller]
SelectList selectList = new SelectList((IEnumerable<Category>)ConvertCategoryToList(dt1), "CategoryID", "CategoryName");
ViewData["categories"] = selectList;
There is a lot missing from your sample (e.g.what a category looks like, what the Edit actions look like, what is dt1, what the model is you pass to the view etc), but I will try based on what is shown.
Problem 1: Can't use foreach in binding
You can't use a foreach with a collection of form items. The items have no way of knowing which individual element to bind with (when they are sent back to the server they need more information to make each entry unique).
Solution:
It only knows how to bind if you use indexing (e.g. using for (int i=0; < count; i++){ #Html.DropDownListFor(model=>item[i]...)
Problem 2: Selected values only can come from SelectList!
This is the most irritating feature of DropDownListFor and appears to be a bug. It will not take the current selected value from the bound data. It will only take a current value from a SelectList, which means you need a unique SelectList for every dropdown.
Solution:
Create a unique SelectList in the view, per drop down required, with the item value as the current selection.
With some faking of your data, I got the following working:
Example
Controller:
Only store the list of items for the SelectList in the ViewBag:
ViewData["categories"] = ConvertCategoryToList(dt1);
View:
1. You need to pass a List and not an IEnumerable as IEnumerable cannot be indexed.
#model List<MyApplication.Item>
2. Create a SelectList for each dropdown
SelectList newSelectList = new SelectList((IEnumerable<MyApplication.Category>)ViewData["categories"], "CategoryID", "CategoryName", Model[i].Id);
3. Use the indexing method for addressing your items in the collection.
#Html.DropDownListFor(m => Model[i].Id, newSelectList, "Select an item")
Problem 3: What data to pass?
The other issue with your code, as-it-stands, is what to pass back and forth to/from the edit view? At the moment I would guess (from the variable name dt1) you are passing a DataTable(?). You will need to be very explicit about the data you are using in order to get a clean solution to this one. I would suggest posting a second question with all your code and Razor view HTML.
If you need to see more of my sample code (below), please post your own code so I can make them consistent.
Full dummy controller code below
public class TestController : Controller
{
public List<Category> dt1 { get; set; }
public TestController()
{
this.dt1 = new List<Category>();
for (int i = 1; i <= 10; i++)
{
this.dt1.Add(new Category() { CategoryId = i, CategoryName = string.Format("Category {0}", i) });
}
}
[HttpGet]
public ActionResult Edit()
{
//SelectList selectList = new SelectList((IEnumerable<Category>)ConvertCategoryToList(dt1), "CategoryID", "CategoryName");
ViewData["categories"] = ConvertCategoryToList(dt1);
List<Item> items = new List<Item>();
items.Add(new Item(){Id = 1});
items.Add(new Item(){Id = 2});
items.Add(new Item(){Id = 3});
items.Add(new Item(){Id = 4});
items.Add(new Item(){Id = 5});
return View(items);
}
[HttpPost]
public ActionResult Edit(FormCollection form)
{
// Turn form submission back into a compatible view model
List<Item> items = new List<Item>();
foreach (string key in form.Keys)
{
string val = form[key];
items.Add(new Item() { Id = int.Parse(val) });
}
// Recreate the select list
ViewData["categories"] = ConvertCategoryToList(dt1);
return View(items);
}
List<Category> ConvertCategoryToList(IEnumerable<Category> dt)
{
return dt.ToList();
}
}
Note: The post version of Edit simply recreates the list of data (using the selected values posted back) and returns to the Edit view. This is just for testing.
Screen shot
Dummy category class
public class Category
{
public int CategoryId { get; set; }
public string CategoryName { get; set; }
}
Full test View
#model List<MyApplication.Item>
#using (Html.BeginForm())
{
for (int i = 0; i < Model.Count; i++)
{
SelectList newSelectList = new SelectList((IEnumerable<MyApplication.Category>)ViewData["categories"], "CategoryID", "CategoryName", Model[i].Id);
#Html.DropDownListFor(m => Model[i].Id, newSelectList, "Select an item")
}
<input type="submit" value="Submit"/>
}

View not binding correcty with the model

I can figure out why it's not binding. So I have a form where a ListBox is in a partial view which I reload everytime I click on a checkbox to fill the listbox.
The code of my ModelView for the form is :
<div class="row-fluid">
<div class="span3">
<label>Fonction(s):</label>
</div>
<div class="span9" id="ListeFonction">
#Html.Partial("ListerFonction", Model)
</div>
</div>
<div class="row-fluid">
<div class="span5 offset3">
<div class="fonctions_container">
#foreach (extranetClient.Models.Classes.FonctionContact fonction in ViewBag.Fonctions)
{
string coche = "";
if ((#Model.ListeFonctions).Any(c => c.IdFonction == fonction.IdFonction))
{
coche = "checked";
}
<input type="checkbox" #coche class="checkbox" value="#fonction.IdFonction" />#fonction.LibelleFonction <br />
}
</div>
</div>
</div>
So as you can see, I render a partial view just after the "Email" Textbox. The code for it is :
#Html.LabelFor(contact => contact.SelectedFonctionIds, "ListeFonctions")
#Html.ListBoxFor(contact => contact.SelectedFonctionIds, new MultiSelectList(Model.ListeFonctions, "IdFonction", "LibelleFonction"), new { disabled = "disabled")
The model associated to that view looks like that:
private List<int> _selectedFonctionIds;
public List<int> SelectedFonctionIds
{
get
{
return _selectedFonctionIds ?? new List<int>();
}
set
{
_selectedFonctionIds = value;
}
}
public List<FonctionContact> ListeFonctions = new List<FonctionContact>();
public MultiSelectList ListeFonctionsSelectList
{
get
{
return new MultiSelectList(
ListeFonctions,
"IdFonction", // dataValueField
"LibelleFonction" // dataTextField
);
}
}
public Contact() { }
public Contact( List<FonctionContact> listeFonctions, List<int> selectedFonctionIds)
{
this.ListeFonctions = listeFonctions;
this.SelectedFonctionIds = selectedFonctionIds;
}
public Contact(int idContact, string nom, string prenom, string email, string telephoneFixe, string telephonePort) {
this.IdContact = idContact;
this.Nom = nom;
this.Prenom = prenom;
this.Email = email;
this.TelephoneFixe = telephoneFixe;
this.TelephonePort = telephonePort;
}
public Contact(int idContact, string nom, string prenom, List<int> selectedFonctionIds, List<FonctionContact> listeFonctions, string email, string telephoneFixe, string telephonePort)
{
this.IdContact = idContact;
this.Nom = nom;
this.Prenom = prenom;
this.SelectedFonctionIds = selectedFonctionIds;
this.ListeFonctions = listeFonctions;
this.Email = email;
this.TelephoneFixe = telephoneFixe;
this.TelephonePort = telephonePort;
}
But the ListBox of the partial view is not binding with the model. I get well the other informations but not these in the listbox. Somebody has an idea ?
Why are you forcing the ListBox's id here:
#Html.ListBoxFor(contact => contact.SelectedFonctionIds,
new MultiSelectList(Model.ListeFonctions, "IdFonction", "LibelleFonction"),
new { disabled = "disabled", **id="idFonctions"** })
ListBoxFor helper is supposed to generate the ListBox's id for you, and the Id should be the same as the attribute it should bind with. Shouldn't it be SelectedFonctionIds?
Was the binding working before you started using the PartialView? Because from your previous question, I see that you had:
#Html.ListBoxFor(contact => contact.SelectedFonctionIds, Model.ListeFonctionsSelectList, new { disabled = "disabled" })
in your View (i.e., you didn't set the id attribute).

MVC4 Dropdownlist

I need to pass values from three dropdownlists to the controller when user selects some value from any one of the dropdownlist.i tried like this but the value from only the dropdown selected is passed others are null values ,any help would be appreciated.
VIEW
##using (Html.BeginForm("GetFilterValues","Home",FormMethod.gET))
{
#Html.DropDownList("FClass", ViewBag.Market as SelectList, new { id = "Market" , onchange = "$(this).parents('form').submit();" })
}
#using (Html.BeginForm("GetFilterValues","Home",FormMethod.Get))
{
#Html.DropDownList("FClass", ViewBag.Class as SelectList, new { id = "FClass" , onchange = "$(this).parents('form').submit();" })
}
</td>
<td>
#Html.Label("Status")
</td>
<td>
#using (Html.BeginForm("GetFilterValues","Home",FormMethod.Get))
{
#Html.DropDownList("Status", ViewBag.Status as SelectList, new { id = "Status" , onchange = "$(this).parents('form').submit();" })
}
CONTROLLER
[HttpgET]
public void GetFilterValues()
{
string market = this.Request.Form.Get("Market");
string fclass = this.Request.Form.Get("FClass");
string status = this.Request.Form.Get("Status");
}
Try a single form trough a POST and pull the values by name using a FormCollection like this...
View:
#using (Html.BeginForm("GetFilterValues","Home", FormMethod.Post))
{
#Html.DropDownList("nameMarket", ViewBag.Market as SelectList, new { id = "Market" , onchange = "$(this).parents('form').submit();" })
#Html.DropDownList("nameClass", ViewBag.Class as SelectList, new { id = "FClass" , onchange = "$(this).parents('form').submit();" })
#Html.DropDownList("nameStatus", ViewBag.Status as SelectList, new { id = "Status" , onchange = "$(this).parents('form').submit();" })
}
Controller:
[HttpPost]
public void GetFilterValues(FormCollection collection) {
string market = Convert.ToString(collection["nameMarket"]);
string fclass = Convert.ToString(collection["nameClass"]);
string status = Convert.ToString(collection["nameStatus"]);
}