I am generating the radiobutton list and then trying to select one option on load as below.
Foreach loop in View
#foreach (var myListItem in Model.MyList)
{
#Html.RadioButtonFor(m => m.MyType,myListItem.MyType, new {id = myListItem.MyType, #Checked = (Model.MyTypeId == myListItem.MyTypeId) })
#myListItem.MyType
}
Eventhough the HTML is generated correctly(refer below). The second option is checked instead of 1st even when Model.MyTypeId = 0.
Generated HTML for view
<input id="0" name="MyType" value="Option One" CHECKED="True" type="radio">Option One
<input id="1" name="MyType" value="Option Two " CHECKED="False" type="radio">Option Two
Please suggest how else I can select the desired radio button option by deafult.
The HTML isn't correct actually. You need to do something more along these lines:
#foreach (var myListItem in Model.MyList)
{
if (Model.MyTypeId == myListItem.MyTypeId)
{
#Html.RadioButtonFor(m => m.MyType,myListItem.MyType,
new
{
id = myListItem.MyType,
#Checked = ""
})
}
else
{
#Html.RadioButtonFor(m => m.MyType,myListItem.MyType,
new
{
id = myListItem.MyType,
})
}
#myListItem.MyType
}
Though I can't verify the exact output, it should look something like this:
<input id="0" name="MyType" value="Option One" CHECKED type="radio">
You may have to use null to get it to generate the CHECKED without the ="", but that would be okay too. See, it's not the value that's recognized, it's the attribute itself, so that's why the second one is checked.
Anytime I need a list of radio buttons created from a query, I always reach for this RadioButtonListFor extension method. Works like a charm:
// jonlanceley.blogspot.com/2011/06/mvc3-radiobuttonlist-helper.html
public static MvcHtmlString RadioButtonListFor<TModel, TProperty>(this HtmlHelper<TModel> htmlHelper,
Expression<Func<TModel, TProperty>> expression, IEnumerable<SelectListItem> listOfValues)
{
var metaData = ModelMetadata.FromLambdaExpression(expression, htmlHelper.ViewData);
var sb = new StringBuilder();
sb.Append("<span class='RadioButtonListFor'> ");
if (listOfValues != null)
{
// Create a radio button for each item in the list
foreach (SelectListItem item in listOfValues)
{
// Generate an id to be given to the radio button field
var id = string.Format("{0}_{1}", metaData.PropertyName, item.Value);
// Create and populate a radio button using the existing html helpers
var htmlAttributes = new Dictionary<string, object>();
htmlAttributes.Add("id", id);
if (item.Selected)
htmlAttributes.Add("checked", "checked");
var radio = htmlHelper.RadioButtonFor(expression, item.Value, htmlAttributes);
// Create the html string that will be returned to the client
// e.g. <label<input data-val="true" data-val-required="You must select an option" id="TestRadio_1" name="TestRadio" type="radio" value="1" />Line1</label>
sb.AppendFormat("<label>{0} {1}</label> ", radio, HttpUtility.HtmlEncode(item.Text));
}
}
sb.Append(" </span>");
return MvcHtmlString.Create(sb.ToString());
}
Now, you can generate your Radio Buttons from any collection you have in memory, usually as a property on your ViewModel like this:
public int SelectedPaymentMethodId { get; set; }
public IEnumerable<SelectListItem> PaymentMethodChoices
{
get
{
return from x in dataSourceFoo
select new SelectListItem {
Text = x.TextThing, Value = x.Id, Selected = (x.Id == SelectedPaymentMethodId)
};
}
}
And your View is as simple as:
#Html.RadioButtonListFor(model => model.SelectedPaymentMethodId, Model.PaymentMethodChoices)
Related
I'm doing a management application users have a part where I have a form with a <select></select>
Which is filled from a
#{ Html.RenderAction ("ListaTipoDeUsuarios", new {selected = 0}); }
This (Index.cshtml):
...
<div class="lg-xs-12">
<label>Tipo Usuario</label>
<select name="tipoUsuario" class="form-control" >
#{Html.RenderAction("ListaTipoDeUsuarios", new { selected = 0 });}
</select>
</div>
....
I have my function in the controller which performs the query to bring the list of types of users (HomeController.cs)
[ChildActionOnly]
public PartialViewResult ListaTipoDeUsuarios()
{
string dtTipoUser = client.GetTiposUsuario("{}");
DataTable dt = (DataTable)JsonConvert.DeserializeObject(dtTipoUser, typeof(DataTable));
List<TipoUsuarioBO> listaTiposUsuarios = new List<TipoUsuarioBO>();
foreach (DataRow row in dt.Rows)
{
TipoUsuarioBO tipoUsuario = new TipoUsuarioBO();
tipoUsuario = TiposUsuarioBR.MapeoTipoUsuario(row, tipoUsuario);
listaTiposUsuarios.Add(tipoUsuario);
}
return PartialView(listaTiposUsuarios);
}
And my view with the list (ListaTipoDeUsuarios.cshtml)
#foreach (var item in Model)
{
<option value="#item.Id">#item.Id - #item.Descripcion</option>
}
My question is, how to make when loading the list brings one of the selected item.Currently when charging the view brings selected by default the first item in the list.
NOTE: Try changing the "0" of the "new selected = {0}" but does nothing.
You will need to change the Model of the PartialView which is rendering the options. You have 2 options.
Change the existing TipoUsuarioBO object to add another property named SelectedID,
OR
Create a new Model with the following declaration.
public class OptionsModel <-- Rename to naming conventions
{
public List<TipoUsuarioBO> TipoUsuarioBO { get; set; }
public int SelectedID {get; set; }
}
And, while rendering option elements, use the following
#foreach (var item in Model.TipoUsuarioBO)
{
<option value="#item.Id" #Html.Raw(#item.Id == Model.SelectedID ? "selected" : "") >#item.Id - #item.Descripcion</option>
}
Why you don't try using List<SelectListItem> as the model of ListaTipoDeUsuarios.cshtml view.
[ChildActionOnly]
public PartialViewResult ListaTipoDeUsuarios()
{
string dtTipoUser = client.GetTiposUsuario("{}");
DataTable dt = (DataTable)JsonConvert.DeserializeObject(dtTipoUser, typeof(DataTable));
List<SelectListItem> listaTiposUsuarios = new List<SelectListItem>();
foreach (DataRow row in dt.Rows)
{
TipoUsuarioBO tipoUsuario = new TipoUsuarioBO();
tipoUsuario = TiposUsuarioBR.MapeoTipoUsuario(row, tipoUsuario);
listaTiposUsuarios.Add(new SelectListItem()
{
Text = tipoUsuario.Id+"-"+tipoUsuario.Descripcion,
Value = tipoUsuario.Id.ToString(),
Selected = true //if you want this item selected otherwise false
});
}
return PartialView(listaTiposUsuarios);
}
and your view
#Html.DropDownList("The name of the field", Model, new { #class = "any-class"})
In my MVC application I have a view where I will display different data from a SQL table. This will generate different amount of drop down lists and text boxes, depending on what is passed in from the Model.
My issue is if I want to then use that data I can't seem to figure out how I can relate control X to object Y in SQL. For example, if I have 2 textboxes that I want to do an update on, then when the Post happens in my application the FormCollection parameter will let me see the Value of the objects, but not their control name or any form of identifying factor.
I could set the Value to a combination of the entered value + a name, then split this, but it seems very much like a lazy workaround.
I've tried to assign an ID to each, for example:
#foreach (DataObject item in Model.AllDataObjects)
{
<tr>
<td>
#Html.DisplayFor(modelItem => item.Name)
</td>
<td>
#Html.DisplayFor(modelItem => item.Data)
</td>
<td>
#if (item.Rule.Contains("Yes;No"))
{
#Html.DropDownListFor(model => item.Value, new List<SelectListItem>
{
new SelectListItem {Text="Yes", Value="Yes"},
new SelectListItem {Text="No", Value="No" }
}, new { #id = item.ObjectId });
}
else
{
#Html.TextAreaFor(model => item.Value, new { style = "width: 400px;", #rows = 5, #id = item.ObjectId })
}
</td>
</tr>
}
Edit: The following is my Post ActionResult method in the Controller, albeit it isn't complete as I can't figure out how to get an ID for the control from the FormCollection
[HttpPost]
[ValidateInput(false)]
public ActionResult UpdateData(FormCollection collection, int objectId=0)
{
try
{
int propertyTypeId = 0;
string propertyValue = string.Empty;
// Get all the control values from the collection
string[] allValues = new string[] { };
IValueProvider valueProvider = collection.ToValueProvider();
foreach(string key in collection.Keys)
{
ValueProviderResult result = valueProvider.GetValue(key);
allValues = result.RawValue as string[];
}
ObjectData objectData = _execution.GetObjectDetails(0);
UpdateDataResponse result = _execution.UpdateData(0, objectId,
objectValue, UserName);
return RedirectToAction("Details",
new { ObjectId = objectData.ObjectId, error = result.ErrorMessage });
}
catch (Exception ex)
{
// My exception handling here
}
}
So I can see in the mark-up that the controls are assigned the object ID as their own ID, but how can I get this back? When I check FormCollection I only see the values for each control, but no way of identifying which is which.
Edit: I'm using MVC version 4.
A form only submits the values of its successful controls (as name/value pairs based on the controls name and value attributes) so if you do not generate a control for the ObjectId properties, they will not be submitted.
However, you current use of foreach loop will not allow you to obtain any meaning information from the data which is posted because all your names are identical and there is no way to reliable match up which value belongs to which item in the collection. Instead use a for loop or EditorTemplate in the view and bind to your model, rather than using FormCollection.
The view should be
#for (int i = 0; i < Model.AllDataObjects.Count; i++)
{
<tr>
<td>#Html.DisplayFor(m => m.AllDataObjects[i].Name)</td>
<td>#Html.DisplayFor(m => m.AllDataObjects[i].Data)</td>
<td>
#Html.HiddenFor(m => m.AllDataObjects[i].ObjectId)
#if (Model.AllDataObjects[i].Rule.Contains("Yes;No"))
{
#Html.DropDownListFor(m => m.AllDataObjects[i].Value, new SelectList(new string[]{ "Yes", "No" }));
}
else
{
#Html.TextAreaFor(m => m.AllDataObjects[i].Value, new { style = "width: 400px;", #rows = 5 })
}
</td>
</tr>
}
And assuming the model in the view is #model MyModel, change the POST method to
[HttpPost]
[ValidateInput(false)]
public ActionResult UpdateData(MyModel model)
and the value of model.AllDataObjects will contain a collection with its ObjectId and Value properties correctly bound.
For more information on why using a foreach loop will not work, refer to this answer.
I am creating a list of months for a list box. The controller captures the selected months and stores them in session for if the user navigates away from the page then returns.
Here is the controller:
public ActionResult Index(int[] Months)
{
if (Session["Months"] == null || Months!= null)
Session["Months"] = Months;
else if (Months== null)
Months= Session["Months"] as int[];
IList<SelectListItem> MonthsList = utility.GetMonths().OrderBy(r => r.Name)
.Select(r => new SelectListItem
{
Text = r.Name,
Value = r.Id.ToString(),
Selected = Months == null ? false : Months.Contains(r.Id)
}).ToList();
var model = new DataModel
{
SelectList = MonthsList,
Data = GetDataByMonths(Months)
};
return (model);
}
Here is the view:
#Html.ListBox("Months", Model.SelectList)
When the user selects items from the ListBox they are highlighted even after the form has been submitted. However when the user navigates away then returns the SelectListItems are correctly labeled as Selected = true but the DOM does not show this.
Any ideas on why this only doesnt work when session is used?
EDIT:
Tried:
#Html.ListBox("Months", new MultiSelectList(Model.Months, "Value", "Text", Model.SelectedMonths), new { size = 8 })
While debugging, the variables show the correct values, they are just not correctly highlighted in the DOM.
Did you try the SelectList type or MultiSelectList rather than an IEnumerable<SelectListItem>? I don't know of any other way to tell the ListBox which property is the value and which is the text.
i.e.
MultiSelectList list = new MultiSelectList(monthsList, "Value", "Text");
and return the list object?
I ended up creating the list box in html rather than using the #html.listbox()
<select name="Months" id="Months" multiple="multiple" size="8">
#foreach (var a in Model.Months)
{
<option value="#a.Value" #(a.Selected.ToString() == "True" ? "selected='selected'" : "")>#a.Text</option>
}
</select>
if I have something like this:
#{
var cats = GetCategories();
var selectList = from c in cats
select new SelectListItem
{
Selected = (c.Id == Model.SessionCategory.Id),
Text = c.Name,
Value = c.Id.ToString(),
};
}
#Html.DropDownList("categories", selectList)
The markup would be like this:
<select id="categories" name="categories">
<option value="1">Category1</option>
<option value="2">Category2</option>
<option selected="selected" value="3">Category3</option>
</select>
And now, the question is:
Is it possible to add additional attributes to each <option> tag?
I mean from the Razor template. Without jQuery workarounds?
I think the most practical solution would be some jQuery or maybe something like this..
<select id="categories" name="categories">
#foreach (var item in selectList) {
<option #if (item.Selected) { <text>selected="selected"</text>} value="#item.Value">#item.Text</option>
}
</select>
you could obviously add in attributes as needed...
By default, no. The SelectListItem does not contain any additional properties to add your attributes to. However, you could create your own DropDownList method or DropDownListFor and create your own ListItemToOption with a custom SelectListItem to add your own attributes.
But it's probably overkill.
Here's how I did it:
I created my own DropDownListFor:
public static MvcHtmlString TheDropDownListFor<TModel, TProperty>(this HtmlHelper<TModel> htmlHelper, Expression<Func<TModel, TProperty>> expression, IEnumerable<SelectListItem> listOfValues, string placeHolder)
{
var model = htmlHelper.ViewData.Model;
var metaData = ModelMetadata .FromLambdaExpression(expression, htmlHelper.ViewData);
var tb = new TagBuilder("select");
if (listOfValues != null)
{
tb.MergeAttribute("id", metaData.PropertyName);
tb.MergeAttribute("name", metaData.PropertyName);
if (!string.IsNullOrEmpty(placeHolder))
{
var option = new TagBuilder("option");
option.MergeAttribute("value", placeHolder);
tb.InnerHtml += option.ToString();
}
foreach (var item in listOfValues)
{
var option = new TagBuilder("option");
option.MergeAttribute("value", item.Value);
var textNdata = item.Text.Split('|');
option.InnerHtml = textNdata[0];
if (textNdata.Length == 2)
option.MergeAttribute("data-name", textNdata[1]);
if(item.Selected)
option.MergeAttribute("selected", "selected");
tb.InnerHtml += option.ToString();
}
}
return MvcHtmlString.Create(tb.ToString());
}
Then my SelectListItem List is created like this:
public List<SelectListItem> EmployerList
{
get
{
return Employers.Select(x => new SelectListItem
{
Text = x.EAN + "|" + x.Name,
Value = x.Id.ToString(),
Selected = (SelectedEmployer != null && SelectedEmployer.Id == x.Id)
}).ToList();
}
}
I almost have this solved but need a little push.
Here's what I have:
In the database I have a field called active that is a bit field (True/False)
I have placed a dropdownlist on the View form like this:
<%= Html.DropDownList("lstActive", new SelectList((IEnumerable)ViewData["ActiveList"])) %>
In my controller, I simply have this code to generate the True/False in the dropdown:
List<string> activeList = new List<string>();
activeList.Add("True");
activeList.Add("False");
ViewData["ActiveList"] = new SelectList(activeList);
I want to bind to the field in the database called active and select it in the dropdown. When I view it like this I get this:
alt text http://rjmueller.net/sitesimages/temp/dropdown.gif
So the questions are these:
Obviously I am not pointing to the Value and Text property but what is that in this case?
And how do I select the value that is in the database?
Any help would be appreciated.
First, this is probably better suited to radio buttons, not a select. Second, you really ought to have a view model with a property that is an IEnumerable<SelectListItem> that supplies the values for the select. You can construct that directly in the model.
var model = new ViewModel();
model.ActiveList = new List<SelectListItem>
{
new SelectListItem { Text = "Yes", Value = "true" },
new SelectListITem { Text = "No", Value = "false" }
};
model.Active = false; // this will be the default
return View( model );
Then in your view (strongly-typed to your view model type):
<%= Html.DropDownListFor( m => m.Active, Model.ActiveList ) %>
Using radio buttons, you can omit the list (since there are only the two choices).
<%= Html.RadioButtonFor( m => m.Active, true ) %> Yes
<%= Html.RadioButtonFor( m => m.Active, false ) %> No
Here's a couple of suggestions for you.
First, your DropdownList's name is "lstActive", so if you create a List<SelectListItem> called "lstActive" and pass that back in ViewData, you don't have to do anything fancy with boxing. Then your declaration looks like:
<%= Html.DropDownList("lstActive") %>
easy, huh?
In your controller, you create your List. Here's a method I've used:
private List<SelectListItem> GetAccounts(User user)
{
var items = new List<SelectListItem>();
foreach (Account account in user.Accounts)
{
var item = new SelectListItem();
item.Text = account.Name;
item.Value = account.AccountId.ToString();
if (ActiveAccount == account.AccountId)
item.Selected = true;
items.Add(item);
}
return items;
}
Basically, what I'm trying to point out is that you can set a property on your SelectListItem that you wish to be displayed as selected. Here, I'm using my own code for Users and Accounts, but you'd substitute your own data based on your db query.
First thing, you're recreating a SelectList the ViewData data, you should declare the DropBox as follows:
<%= Html.DropDownList("lstActive", ViewData["ActiveList"]) %>
Second, instead of creating a generic list on the controller, create a SelectList and add SelectListItems to it:
var activeList = new SelectList
{
new SelectListItem { Text = "True", Value = true },
new SelectListItem { Text = "False", Value = false }
};
ViewData["ActiveList"] = activeList;
This should clarify:
Drop-down Lists and ASP.NET MVC
For each select list element you need to set the Text and Value properties...
One solution could be as follows:
Model:
public class NameValue
{
public string Name { get; set; }
public string Value { get; set; }
}
Controller:
string currentActiveValue = myDB.active.ToString();
List<NameValue> yesNoList = new List<NameValue>
{
new NameValue { Name = "Yes", Value = "True" },
new NameValue { Name = "No", Value = "False" }
};
SelectList myActiveList = new SelectList(yesNoList, "Name", "Value", currentActiveValue);
ViewData["ActiveList"] = myActiveList;
View:
div>Is Active: <%= Html.DropDownList("ActiveList") %></div>