I Create a one web API. its main aim is a request to another server and get the response from that server.
I successfully get the response for a particular server.
I get the response(its a JSON Format) is below.
{
"id": "test#gmail.com",
"active": 1,
"is_logged": true,
"token": "hsja3t56yJKV1QiLCJhbGciOiJIUzI1NiJ9.eyJ1c2VybmFtZSI6InRlc3RAZHZlby5jb20iLCJwYXNzd29yZCI6InRlc3QyMDE4KyIsImV4cGlyZU9uIjoiMjAxOS0wNi0yMVQwNTozNzowOC4xODhaIn0.3wgGeL_HvcoEJJeEF7tj8jeXk2uIKpOoi9ewmK5yhteh",
"status": "OK",
"usertype": "TestUser",
"msg": "Login Successfull."
}
I try to separate using split function
string[] sep = response.Split(',');
foreach (string any in sep)
Console.WriteLine(any);
//string[] colon = sep[0].Split(':');
string[][] colon = sep.Select(x => x.Split(':')).ToArray();
//int count = colon.Count();
for (int i = 0; i <= colon.Length; i++)
{
Console.WriteLine(colon[i][0]);
Console.WriteLine(colon[i][1]);
}
Any other way to separate the response? I also use all the field in some other purpose.
Create a Class based on your response property:
public class UserData
{
public string id { get; set; }
public int active { get; set; }
public bool is_logged { get; set; }
public string token { get; set; }
public string status { get; set; }
public string usertype { get; set; }
public string msg { get; set; }
}
On reading the response data, use JsonConvert.DeserializeObject
string response = "{\"id\":\"test #gmail.com\",\"active\":1,\"is_logged\":true,\"token\":\"hsja3t56yJKV1QiLCJhbGciOiJIUzI1NiJ9.eyJ1c2VybmFtZSI6InRlc3RAZHZlby5jb20iLCJwYXNzd29yZCI6InRlc3QyMDE4KyIsImV4cGlyZU9uIjoiMjAxOS0wNi0yMVQwNTozNzowOC4xODhaIn0.3wgGeL_HvcoEJJeEF7tj8jeXk2uIKpOoi9ewmK5yhteh\",\"status\":\"OK\",\"usertype\":\"TestUser\",\"msg\":\"Login Successfull.\"}";
var responseData = JsonConvert.DeserializeObject<UserData>(response);
//here the print in JSON Data
Console.WriteLine("id : " + responseData.id);
Console.WriteLine("active : " + responseData.active);
Console.WriteLine("is_logged : " + responseData.is_logged);
Console.WriteLine("token : " + responseData.token);
Console.WriteLine("status : " + responseData.status);
Console.WriteLine("usertype : " + responseData.usertype);
Console.WriteLine("msg : " + responseData.msg);
use Newtonsoft.json.dll by adding the NuGet package,
Then convert the response to json object
JObject jo = JObject.Parse(searchCondition);
foreach (JToken child in jo.Children()) {
var prop = child as JProperty;
if (prop.Value != null && !string.IsNullOrEmpty(prop.Value.ToString())) {
string name=prop.Name;
string value = prop.Value;
//You can now do whatever with the values like put in a list of object
}
}
This is My own example to get the properties from JSON string, you can use this.
But first, you need to install this package:-> Newtonsoft.Json.Linq to access JObject
using System;
using Newtonsoft.Json.Linq;
public class Program
{
public static void Main()
{
string jsonString = "{\"firstname\":\"Alex Wu\",\"lastname\":\"type\"}";
JObject jObject = JObject.Parse(jsonString);
string firstname = (string)jObject.SelectToken("firstname");
string lastname = (string)
Console.WriteLine("{0}", firstname);
Console.ReadLine();
}
}
I'm developing an ASP.NET MVC 5 application, with C# and .NET Framework 4.6.1.
I have this View:
#model MyProject.Web.API.Models.AggregationLevelConfViewModel
[...]
#Html.DropDownListFor(m => m.Configurations[0].HelperCodeType, (SelectList)Model.HelperCodeTypeItems, new { id = "Configurations[0].HelperCodeType" })
The ViewModel is:
public class AggregationLevelConfViewModel
{
private readonly List<GenericIdNameType> codeTypes;
private readonly List<GenericIdNameType> helperCodeTypes;
public IEnumerable<SelectListItem> CodeTypeItems
{
get { return new SelectList(codeTypes, "Id", "Name"); }
}
public IEnumerable<SelectListItem> HelperCodeTypeItems
{
get { return new SelectList(helperCodeTypes, "Id", "Name"); }
}
public int ProductionOrderId { get; set; }
public string ProductionOrderName { get; set; }
public IList<Models.AggregationLevelConfiguration> Configurations { get; set; }
public AggregationLevelConfViewModel()
{
// Load CodeTypes to show it as a DropDownList
byte[] values = (byte[])Enum.GetValues(typeof(CodeTypes));
codeTypes = new List<GenericIdNameType>();
helperCodeTypes = new List<GenericIdNameType>();
for (int i = 0; i < values.Length; i++)
{
GenericIdNameType cType = new GenericIdNameType()
{
Id = values[i].ToString(),
Name = EnumHelper.GetDescription((CodeTypes)values[i])
};
if (((CodeTypes)values[i]) != CodeTypes.NotUsed)
codeTypes.Add(cType);
helperCodeTypes.Add(cType);
}
}
}
And Models.AggregationLevelConfiguration is:
public class AggregationLevelConfiguration
{
public byte AggregationLevelConfigurationId { get; set; }
public int ProductionOrderId { get; set; }
public string Name { get; set; }
public byte CodeType { get; set; }
public byte HelperCodeType { get; set; }
public int PkgRatio { get; set; }
public int RemainingCodes { get; set; }
}
I need to set selected value in these properties:
public IEnumerable<SelectListItem> CodeTypeItems
{
get { return new SelectList(codeTypes, "Id", "Name"); }
}
public IEnumerable<SelectListItem> HelperCodeTypeItems
{
get { return new SelectList(helperCodeTypes, "Id", "Name"); }
}
But I can't set it in new SelectList(codeTypes, "Id", "Name"); or new SelectList(helperCodeTypes, "Id", "Name"); because the selected value are in Configurations array: fields AggregationLevelConfiguration.CodeType and AggregationLevelConfiguration.HelperCodeType.
I think I have to set selected value in the View, but I don't know how to do it.
How can I set the selected values?
Unfortunately #Html.DropDownListFor() behaves a little differently than other helpers when rendering controls in a loop. This has been previously reported as an issue on CodePlex (not sure if its a bug or just a limitation)
The are 2 option to solve this to ensure the correct option is selected based on the model property
Option 1 (using an EditorTemplate)
Create a custom EditorTemplate for the type in the collection. Create a partial in /Views/Shared/EditorTemplates/AggregationLevelConfiguration.cshtml (note the name must match the name of the type
#model yourAssembly.AggregationLevelConfiguration
#Html.DropDownListFor(m => m.HelperCodeType, (SelectList)ViewData["CodeTypeItems"])
.... // other properties of AggregationLevelConfiguration
and then in the main view, pass the SelectList to the EditorTemplate as additionalViewData
#using (Html.BeginForm())
{
...
#Html.EditorFor(m => m.Configurations , new { CodeTypeItems = Model.CodeTypeItems })
...
Option 2 (generate a new SelectList in each iteration and set the selectedValue)
In this option your property CodeTypeItems should to be IEnumerable<GenericIdNameType>, not a SelectList (or just make codeTypes a public property). Then in the main view
#Html.DropDownListFor(m => m.Configurations[0].HelperCodeType, new SelectList(Model.CodeTypeItems, "Id", "Name", Model.Configurations[0].HelperCodeType)
Side note: there is no need to use new { id = "Configurations[0].HelperCodeType" - the DropDownListFor() method already generated that id attribute
I wrote this class to overcome an issue I was having with selecting an option in an html select list. I hope it helps someone.
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Web;
namespace Login_page.Models
{
public class HTMLSelect
{
public string id { get; set; }
public IEnumerable<string> #class { get; set; }
public string name { get; set; }
public Boolean required { get; set; }
public string size { get; set; }
public IEnumerable<SelectOption> SelectOptions { get; set; }
public HTMLSelect(IEnumerable<SelectOption> options)
{
}
public HTMLSelect(string id, string name)
{
this.id = id;
this.name = name;
}
public HTMLSelect(string id, string name, bool required, IEnumerable<SelectOption> options)
{
this.id = id;
this.name = name;
this.required = required;
}
private string BuildOpeningTag()
{
StringBuilder text = new StringBuilder();
text.Append("<select");
text.Append(this.id != null ? " id=" + '"' + this.id + '"' : "");
text.Append(this.name != null ? " name=" + '"' + this.name + '"' : "");
text.Append(">");
return text.ToString();
}
public string GenerateSelect(IEnumerable<SelectOption> options)
{
StringBuilder selectElement = new StringBuilder();
selectElement.Append(this.BuildOpeningTag());
foreach (SelectOption option in options)
{
StringBuilder text = new StringBuilder();
text.Append("\t");
text.Append("<option value=" + '"' + option.Value + '"');
text.Append(option.Selected != false ? " selected=" + '"' + "selected" + '"' + ">" : ">");
text.Append(option.Text);
text.Append("</option>");
selectElement.Append(text.ToString());
}
selectElement.Append("</select");
return selectElement.ToString();
}
}
public class SelectOption
{
public string Text { get; set; }
public Boolean Selected { get; set; }
public string Value { get; set; }
}
}
And
public IEnumerable<SelectOption> getOrderTypes()
{
List<SelectOption> orderTypes = new List<SelectOption>();
if (this.orderType == "OptionText")
{
orderTypes.Add(new SelectOption() { Value = "1", Text = "OptionText", Selected = true });
} else
{
orderTypes.Add(new SelectOption() { Value = "2", Text = "OptionText2" });
}
}
And to use it:
#{
Login_page.Models.HTMLSelect selectElement = new Login_page.Models.HTMLSelect("order-types", "order-types");
}
#Html.Raw(selectElement.GenerateSelect(Model.getOrderTypes()));
I leave this in case it helps someone else. I had a very similar problem and none of the answers helped.
We had in a view this line at the top:
IEnumerable<SelectListItem> exitFromTrustDeed = (ViewData["ExitFromTrustDeed"] as IEnumerable<string>).Select(e => new SelectListItem() {
Value = e,
Text = e,
Selected = Model.ExitFromTrustDeed == e
});
and then below in the view:
#Html.DropDownListFor(m => m.ExitFromTrustDeed, exitFromTrustDeed, new { #class = "form-control" })
We had a property in my ViewData with the same name as the selector for the lambda expression and for some reason that makes the dropdown to be rendered without any option selected.
We changed the name in ViewData to ViewData["ExitFromTrustDeed2"] and that made it work as expected.
Weird though.
I am trying to make cascading dropdown list in ASP.NET MVC4, both values for my dropdown list's comes from methods, so am in trouble how to pass value form one dropdown list to another.
Here's how I get values for the first dropdown list:
var CampaignInfo1 = CampaignManagementService.GetAdvertisers((string)Session["ticket"]);
List<CampaignList1> items1 = new List<CampaignList1>();
foreach (var element in CampaignInfo1)
{
items1.Add(new CampaignList1() { ID1 = element.Key, Name1 = element.Value });
}
var listOfCamp1 = new SelectList(items1, "ID1", "Name1", 1);
ViewData["list1"] = listOfCamp1;
And dropdown list in view:
#Html.DropDownList("list1", ViewData["list1"] as SelectList, "-- Select Client -1-")
The second dropdown list value am getting almost same method:
var CampaignInf = CampaignManagementService.GetCampaigns((string)Session["ticket"], IDFromfirstDDL);
List<AlreadyCreatedCampaignList> itemas = new List<AlreadyCreatedCampaignList>();
foreach (var element in CampaignInf)
{
itemas.Add(new AlreadyCreatedCampaignList() { campID = element.Key, campName = element.Value });
}
var listOfCam = new SelectList(itemas, "campID", "campName", 1);
ViewData["clist"] = listOfCam;
But there is a problem that in method GetCampaigns I have to pass the id(IDFromfirstDDL) which I get from first DDL, and only then method return values which are for that id.
The problem is that I don't know how to pass that selected value from first DDL to second, without any form submit, because I need that second DDL changes his values immediately after first DDL changes.
i made it combining http://kruisit.nl/articles/asp.net-mvc-linked-dropdown/ and http://www.appelsiini.net/projects/chained jquery chained selector this article
currently using in my site
public static class LinkedDropdownHelper
{
#region Methods
public static MvcHtmlString LinkedDropdownListFor<TModel, TProperty>(this HtmlHelper<TModel> htmlHelper, Expression<Func<TModel, TProperty>> expression, string parent, IEnumerable<LinkedSelectListItem> selectList ,bool removedefault=false)
{
ModelMetadata metadata = ModelMetadata.FromLambdaExpression( expression,htmlHelper.ViewData );
var selectedvalue = metadata.Model;
string propertyName = metadata.PropertyName;
TagBuilder select = new TagBuilder("select");
select.Attributes.Add("id", propertyName);
select.Attributes.Add("name", propertyName);
//select.Attributes.Add("class", "linked-dropdown");
select.Attributes.Add("class", parent);
foreach (var item in selectList)
{
if (removedefault && item.Value == "-1")
{
//skip default
}
else
{
TagBuilder option = new TagBuilder("option");
option.InnerHtml = item.Text;
option.Attributes.Add("value", item.Value);
option.Attributes.Add("class", item.LinkValue);
if (item.Selected)
{
option.Attributes.Add("selected", "selected");
}
select.InnerHtml += option.ToString(TagRenderMode.Normal);
}
}
//below code was changed by abdurrauf to support jquery chains
string script = #"<script type='text/javascript'>$(document).bind('ready', function(){
$('#" + propertyName + "').chained('#" + parent + "');"+
#"$('select[name=""" + propertyName + #"""]').val("""+selectedvalue+#""");" +
"});</script>";
return MvcHtmlString.Create(script + select.ToString(TagRenderMode.Normal));
}
#endregion Methods
}
public class LinkedSelectList : IEnumerable<LinkedSelectListItem>
{
#region Constructors
public LinkedSelectList(IEnumerable items, string dataValueField, string dataTextField, string dataLinkedValueField, IEnumerable selectedValues)
{
if (items == null)
{
throw new ArgumentNullException("items");
}
Items = items;
DataValueField = dataValueField;
DataTextField = dataTextField;
DataLinkedValueField = dataLinkedValueField;
SelectedValues = selectedValues;
}
#endregion Constructors
#region Properties
public string DataLinkedValueField
{
get; private set;
}
public string DataTextField
{
get; private set;
}
public string DataValueField
{
get; private set;
}
public IEnumerable Items
{
get; private set;
}
public IEnumerable SelectedValues
{
get; private set;
}
#endregion Properties
#region Methods
public virtual IEnumerator<LinkedSelectListItem> GetEnumerator()
{
return GetListItems().GetEnumerator();
}
IEnumerator IEnumerable.GetEnumerator()
{
return GetEnumerator();
}
internal IList<LinkedSelectListItem> GetListItems()
{
return GetListItemsWithValueField();
}
private static string Eval(object container, string expression)
{
object value = container;
if (!String.IsNullOrEmpty(expression))
{
value = DataBinder.Eval(container, expression);
}
return Convert.ToString(value, CultureInfo.CurrentCulture);
}
private IList<LinkedSelectListItem> GetListItemsWithValueField()
{
HashSet<string> selectedValues = new HashSet<string>(StringComparer.OrdinalIgnoreCase);
if (SelectedValues != null)
{
selectedValues.UnionWith(from object value in SelectedValues select Convert.ToString(value, CultureInfo.CurrentCulture));
}
var listItems = from object item in Items
let value = Eval(item, DataValueField)
select new LinkedSelectListItem
{
Value = value,
Text = Eval(item, DataTextField),
LinkValue = Eval(item, DataLinkedValueField),
Selected = selectedValues.Contains(value)
};
return listItems.ToList();
}
#endregion Methods
}
public class LinkedSelectListItem
{
#region Properties
public string LinkValue
{
get; set;
}
public bool Selected
{
get; set;
}
public string Text
{
get; set;
}
public string Value
{
get; set;
}
#endregion Properties
}
I'm trying to implement client validation for my custom type, however i'm not sure how to do it for min/max validators.
model:
[MultilanguagePropertyRequired(ErrorMessageResourceName = "fld_Description_val_Required", ErrorMessageResourceType = typeof(Resources.Service.Controllers.Firm))]
[MultilanguagePropertyStringLength(1000, MinimumLength = 150, ErrorMessageResourceName = "fld_Description_val_MinLength_lbl", ErrorMessageResourceType = typeof(Resources.Service.Controllers.Firm))]
[Display(Name = "fld_Description_lbl", ResourceType = typeof(Resources.Service.Controllers.Firm))]
public MultilanguageProperty<string> Description
{
get
{
return this.GetMultilanguageProperty("Description", string.Empty, this);
}
set
{
this.SetMultilanguageProperty("Description", value);
}
}
this is my custom string length attribute that extends "StringLegth":
[AttributeUsage(AttributeTargets.Property | AttributeTargets.Field, AllowMultiple = true)]
public class MultilanguagePropertyStringLengthAttribute : StringLengthAttribute, IClientValidatable
{
public MultilanguagePropertyStringLengthAttribute(int length) : base(length)
{
}
public override bool IsValid(object value)
{
string strValue = (string)(value as MultilanguageProperty<string>).Value;
return base.IsValid(strValue);
}
public IEnumerable<ModelClientValidationRule> GetClientValidationRules(ModelMetadata metadata, ControllerContext context)
{
yield return new ModelClientValidationRule() { ValidationType = "multilanguagestringlength", ErrorMessage = this.ErrorMessageString };
}
}
then on my view I have this:
..
<script type="text/javascript">
(function ($) {
$.validator.unobtrusive.adapters.addBool("multilanguagerequired", "required");
$.validator.unobtrusive.adapters.addMinMax("multilanguagestringlength", "minlength", "maxlength");
} (jQuery));
</script>
..
which doesn't work. am i missing something here?
thanks
No need to have a custom client side validation. You can try something like this:
[AttributeUsage(AttributeTargets.Field | AttributeTargets.Property, AllowMultiple = false, Inherited = true)]
public sealed class ValidatePasswordLengthAttribute : ValidationAttribute, IClientValidatable {
private const string _defaultErrorMessage = "'{0}' must be between {1} and {2} characters long.";
private readonly int _minCharacters, _maxCharacters;
public ValidatePasswordLengthAttribute(int minLength, int maxLength)
: base(_defaultErrorMessage) {
_minCharacters = minLength;
_maxCharacters = maxLength;
}
public override string FormatErrorMessage(string name) {
return String.Format(CultureInfo.CurrentCulture, ErrorMessageString,
name, _minCharacters, _maxCharacters);
}
public override bool IsValid(object value) {
string valueAsString = value as string;
return (valueAsString != null && valueAsString.Length >= _minCharacters && valueAsString.Length <= _maxCharacters);
}
public IEnumerable<ModelClientValidationRule> GetClientValidationRules(ModelMetadata metadata, ControllerContext context) {
return new[]{
new ModelClientValidationStringLengthRule(FormatErrorMessage(metadata.GetDisplayName()), _minCharacters, _maxCharacters)
};
}
}
It comes from the build-in MVC3 internet project template.
I am solving similar problem in a different way, but hey, try some parts of this code! I mean GetClientValidationRules() method for string length validation.
public sealed class MyStringLengthAttribute : StringLengthAttribute, IClientValidatable
{
private int? labelId;
public MyStringLengthAttribute(int label, int maximumLength)
: base(maximumLength)
{
labelId = label;
}
public override string FormatErrorMessage(string name)
{
if (labelId.HasValue)
{
return String.Format(MyLabel.Label(labelId.Value), name);
}
return String.Format(MyLabel.Default("FieldTooLong_Validation", "Field {0} is too long"), name);
}
public IEnumerable<ModelClientValidationRule> GetClientValidationRules(ModelMetadata metadata, ControllerContext context)
{
StringLengthAttributeAdapter adapt = new StringLengthAttributeAdapter(metadata,context, this);
return adapt.GetClientValidationRules();
}
}
I use the Adapter class I found in .NET framework, and no need for the custom Javascript work.
And follow this if you still want to do custom JS part http://itmeze.com/2010/12/06/checkbox-has-to-be-checked-with-unobtrusive-jquery-validation-and-asp-net-mvc-3/
I too am having the same problem. You are missing ValidationParameters in your GetClientValidationRules:
public IEnumerable<ModelClientValidationRule> GetClientValidationRules(ModelMetadata metadata, ControllerContext context)
{
var rule = new ModelClientValidationRule
{
ErrorMessage = this.ErrorMessage,
ValidationType = "dayrange"
};
rule.ValidationParameters.Add("min", _minimumDays);
rule.ValidationParameters.Add("max", _maximumDays);
yield return rule;
}
I still having problems with the wiring between the jQuery.validator and jQuery.validator.unobtrusive.adapters but here's the code. Hope it helps:
$(function () {
jQuery.validator.addMethod('dayRange', function (value, element, param) {
if (!value) return false;
var valueDateParts = value.split(param.seperator);
var minDate = new Date();
var maxDate = new Date();
var now = new Date();
var dateValue = new Date(valueDateParts[2],
(valueDateParts[1] - 1),
valueDateParts[0],
now.getHours(),
now.getMinutes(),
(now.getSeconds()+5));
minDate.setDate(minDate.getDate() - parseInt(param.min));
maxDate.setDate(maxDate.getDate() + parseInt(param.max));
return dateValue >= minDate && dateValue <= maxDate;
});
jQuery.validator.unobtrusive.adapters.addMinMax('dayrange', 'minlength', 'maxlength', 'dayrange');
}(jQuery));
There was an Html.RadioButtonList extension method in ASP.NET MVC Futures. Has anyone found a code for a strongly typed version RadioButtonListFor<T>. It would look like this in a view:
<%= Html.RadioButtonListFor(model=>model.Item,Model.ItemList) %>
Here is the usage in the aspx page
<%= Html.RadioButtonListFor(m => m.GenderRadioButtonList)%>
Here is the view model
public class HomePageViewModel
{
public enum GenderType
{
Male,
Female
}
public RadioButtonListViewModel<GenderType> GenderRadioButtonList { get; set; }
public HomePageViewModel()
{
GenderRadioButtonList = new RadioButtonListViewModel<GenderType>
{
Id = "Gender",
SelectedValue = GenderType.Male,
ListItems = new List<RadioButtonListItem<GenderType>>
{
new RadioButtonListItem<GenderType>{Text = "Male", Value = GenderType.Male},
new RadioButtonListItem<GenderType>{Text = "Female", Value = GenderType.Female}
}
};
}
}
Here's the view model used for radio button lists
public class RadioButtonListViewModel<T>
{
public string Id { get; set; }
private T selectedValue;
public T SelectedValue
{
get { return selectedValue; }
set
{
selectedValue = value;
UpdatedSelectedItems();
}
}
private void UpdatedSelectedItems()
{
if (ListItems == null)
return;
ListItems.ForEach(li => li.Selected = Equals(li.Value, SelectedValue));
}
private List<RadioButtonListItem<T>> listItems;
public List<RadioButtonListItem<T>> ListItems
{
get { return listItems; }
set
{
listItems = value;
UpdatedSelectedItems();
}
}
}
public class RadioButtonListItem<T>
{
public bool Selected { get; set; }
public string Text { get; set; }
public T Value { get; set; }
public override string ToString()
{
return Value.ToString();
}
}
Here's the extension methods for RadioButtonListFor
public static class HtmlHelperExtensions
{
public static string RadioButtonListFor<TModel, TRadioButtonListValue>(this HtmlHelper<TModel> htmlHelper, Expression<Func<TModel, RadioButtonListViewModel<TRadioButtonListValue>>> expression) where TModel : class
{
return htmlHelper.RadioButtonListFor(expression, null);
}
public static string RadioButtonListFor<TModel, TRadioButtonListValue>(this HtmlHelper<TModel> htmlHelper, Expression<Func<TModel, RadioButtonListViewModel<TRadioButtonListValue>>> expression, object htmlAttributes) where TModel : class
{
return htmlHelper.RadioButtonListFor(expression, new RouteValueDictionary(htmlAttributes));
}
public static string RadioButtonListFor<TModel, TRadioButtonListValue>(this HtmlHelper<TModel> htmlHelper, Expression<Func<TModel, RadioButtonListViewModel<TRadioButtonListValue>>> expression, IDictionary<string, object> htmlAttributes) where TModel : class
{
var inputName = GetInputName(expression);
RadioButtonListViewModel<TRadioButtonListValue> radioButtonList = GetValue(htmlHelper, expression);
if (radioButtonList == null)
return String.Empty;
if (radioButtonList.ListItems == null)
return String.Empty;
var divTag = new TagBuilder("div");
divTag.MergeAttribute("id", inputName);
divTag.MergeAttribute("class", "radio");
foreach (var item in radioButtonList.ListItems)
{
var radioButtonTag = RadioButton(htmlHelper, inputName, new SelectListItem{Text=item.Text, Selected = item.Selected, Value = item.Value.ToString()}, htmlAttributes);
divTag.InnerHtml += radioButtonTag;
}
return divTag + htmlHelper.ValidationMessage(inputName, "*");
}
public static string GetInputName<TModel, TProperty>(Expression<Func<TModel, TProperty>> expression)
{
if (expression.Body.NodeType == ExpressionType.Call)
{
var methodCallExpression = (MethodCallExpression)expression.Body;
string name = GetInputName(methodCallExpression);
return name.Substring(expression.Parameters[0].Name.Length + 1);
}
return expression.Body.ToString().Substring(expression.Parameters[0].Name.Length + 1);
}
private static string GetInputName(MethodCallExpression expression)
{
// p => p.Foo.Bar().Baz.ToString() => p.Foo OR throw...
var methodCallExpression = expression.Object as MethodCallExpression;
if (methodCallExpression != null)
{
return GetInputName(methodCallExpression);
}
return expression.Object.ToString();
}
public static string RadioButton(this HtmlHelper htmlHelper, string name, SelectListItem listItem,
IDictionary<string, object> htmlAttributes)
{
var inputIdSb = new StringBuilder();
inputIdSb.Append(name)
.Append("_")
.Append(listItem.Value);
var sb = new StringBuilder();
var builder = new TagBuilder("input");
if (listItem.Selected) builder.MergeAttribute("checked", "checked");
builder.MergeAttribute("type", "radio");
builder.MergeAttribute("value", listItem.Value);
builder.MergeAttribute("id", inputIdSb.ToString());
builder.MergeAttribute("name", name + ".SelectedValue");
builder.MergeAttributes(htmlAttributes);
sb.Append(builder.ToString(TagRenderMode.SelfClosing));
sb.Append(RadioButtonLabel(inputIdSb.ToString(), listItem.Text, htmlAttributes));
sb.Append("<br>");
return sb.ToString();
}
public static string RadioButtonLabel(string inputId, string displayText,
IDictionary<string, object> htmlAttributes)
{
var labelBuilder = new TagBuilder("label");
labelBuilder.MergeAttribute("for", inputId);
labelBuilder.MergeAttributes(htmlAttributes);
labelBuilder.InnerHtml = displayText;
return labelBuilder.ToString(TagRenderMode.Normal);
}
public static TProperty GetValue<TModel, TProperty>(HtmlHelper<TModel> htmlHelper, Expression<Func<TModel, TProperty>> expression) where TModel : class
{
TModel model = htmlHelper.ViewData.Model;
if (model == null)
{
return default(TProperty);
}
Func<TModel, TProperty> func = expression.Compile();
return func(model);
}
}
MVC 3 example which creates 3 radio buttons with validation to ensure 1 option is selected. And if the form fails validation (e.g. on other fields) the chosen radio option is preselected when the form is reshown.
View
#Html.RadioButtonForSelectList(m => m.TestRadio, Model.TestRadioList)
#Html.ValidationMessageFor(m => m.TestRadio)
Model
public class aTest
{
public Int32 ID { get; set; }
public String Name { get; set; }
}
public class LogOnModel
{
public IEnumerable<SelectListItem> TestRadioList { get; set; }
[Required(ErrorMessage="Test Error")]
public String TestRadio { get; set; }
[Required]
[Display(Name = "User name")]
public string UserName { get; set; }
}
Controller Actions
public ActionResult LogOn()
{
List<aTest> list = new List<aTest>();
list.Add(new aTest() { ID = 1, Name = "Line1" });
list.Add(new aTest() { ID = 2, Name = "Line2" });
list.Add(new aTest() { ID = 3, Name = "Line3" });
SelectList sl = new SelectList(list, "ID", "Name");
var model = new LogOnModel();
model.TestRadioList = sl;
return View(model);
}
[HttpPost]
public ActionResult LogOn(LogOnModel model, string returnUrl)
{
if (ModelState.IsValid)
{
....
}
// If we got this far, something failed, redisplay form
List<aTest> list = new List<aTest>();
list.Add(new aTest() { ID = 1, Name = "Line1" });
list.Add(new aTest() { ID = 2, Name = "Line2" });
list.Add(new aTest() { ID = 3, Name = "Line3" });
SelectList sl = new SelectList(list, "ID", "Name");
model.TestRadioList = sl;
return View(model);
}
Here is the extension:
public static class HtmlExtensions
{
public static MvcHtmlString RadioButtonForSelectList<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();
if (listOfValues != null)
{
foreach (SelectListItem item in listOfValues)
{
var id = string.Format(
"{0}_{1}",
metaData.PropertyName,
item.Value
);
var radio = htmlHelper.RadioButtonFor(expression, item.Value, new { id = id }).ToHtmlString();
sb.AppendFormat(
"<label for=\"{0}\">{1}</label> {2}",
id,
HttpUtility.HtmlEncode(item.Text),
radio
);
}
}
return MvcHtmlString.Create(sb.ToString());
}
}
Okay, I'm aware this isn't a direct answer to your question, but this may be a better way to doing most inputs anyway (and it was fun to make). I have only just completed this and ran a small amount of testing against it, so I can't vouch for this being perfect in every situation.
I got this idea from Jimmy Bogard's post here. Take a look because there's a heap of really cool ideas there.
What I have done is created an "InputFor" helper which tries its best to work out what input you're asking for and outputs it accordingly. This will do radio buttons, but will default to a drop down if there is more than two, you should be able to change this functionality quite easily.
The below code allows you to make calls such as <%= Html.InputFor(m => m.Gender) %> or <%Html.InputFor(m => m.Gender, Model.GenderList)%>. There is a cool little bit at the end which allows you to do coding by convention, but we'll get to that later.
public static MvcHtmlString InputFor<TModel>(this HtmlHelper<TModel> helper, Expression<Func<TModel, object>> field, Dictionary<string, string> listing) where TModel : class
{
string property_name = GetInputName(field);
PropertyDescriptor descriptor = TypeDescriptor.GetProperties(helper.ViewData.Model).Find(property_name, true);
string property_type = descriptor.PropertyType.Name;
var func = field.Compile();
var value = func(helper.ViewData.Model);
//Add hidden element if required
if (descriptor.Attributes.Contains(new HiddenInputAttribute()))
{
return helper.Hidden(property_name, value);
}
if (property_type == "DateTime" || property_type == "Date")
{
return helper.TextBox(property_name, value, new { #class = "date_picker" });
}
if (listing != null)
{
if (listing.Count <= 2)
{
//This is a good length for a radio button
string output = "";
foreach (KeyValuePair<string, string> pair in listing)
{
TagBuilder label = new TagBuilder("label");
label.MergeAttribute("for", property_name);
label.SetInnerText(pair.Value);
output += helper.RadioButton(property_name, pair.Key, (value == pair.Key)).ToHtmlString();
output += label.ToString();
}
return MvcHtmlString.Create(output);
}
else
{
//too big for a radio button, lets make a drop down
return helper.DropDownList(property_name, new SelectList(listing, "Key", "Value"), value);
}
}
else
{
if (property_type == "Boolean")
{
listing = new Dictionary<string, string>();
listing.Add("true", "Yes");
listing.Add("false", "No");
SelectList select_values = new SelectList(listing, "Key", "Value", ((bool)value ? "Yes" : "No"));
return helper.DropDownList(property_name, select_values);
}
return helper.TextBox(property_name, value);
}
}
Coding by Convention
The below code allows this to be done with convention over configuration in mind. An example of this is if you have a model object which contains the property you want to list (Gender) and a dictionary with the same name but appended with "List" (GenderList) then it will use this list by default.
e.g. <%= Html.InputFor(m => m.Gender) %> can make a full drop down list/radio button group, but these default values can be overridden by making a call like <%= Html.InputFor(m => m.Gender, alternate_list) %>
public static MvcHtmlString InputFor<TModel>(this HtmlHelper<TModel> helper, Expression<Func<TModel, object>> field) where TModel : class
{
string property_name = GetInputName(field) + "List";
PropertyDescriptor list_descriptor = TypeDescriptor.GetProperties(helper.ViewData.Model).Find(property_name, true);
Dictionary<string, string> listing = null;
if (list_descriptor != null)
{
//Found a match for PropertyNameList, try to pull it out so we can use it
PropertyInfo temp = helper.ViewData.Model.GetType().GetProperty(property_name);
listing = (Dictionary<string, string>)temp.GetValue(helper.ViewData.Model, null);
}
return InputFor(helper, field, listing);
}
Now a slight disclaimer:
This isn't the fastest code in the world (due to the reflection and other things), in my situation this isn't really relevant as it's all user driven, if you're planning on doing something crazy stupid.
This code is in its infancy, I will be testing this more thoroughly and adding to it over the next few days, open to any suggestions to improve the code.
I hope this code is useful to someone, I know I'll be using it over the next couple of weeks to try and cut down time. Cutting this down to just do the radio button should be a trivial task, good luck :)
Jay
Based in Jon post, a small improve to generate the radio button list as ul with HTMLAttributtes
public static MvcHtmlString RadioButtonListFor<TModel, TProperty>(
this HtmlHelper<TModel> htmlHelper,
Expression<Func<TModel, TProperty>> expression,
IEnumerable<SelectListItem> listOfValues,
IDictionary<string, object> radioHtmlAttributes = null,
string ulClass = null)
{
ModelMetadata metaData = ModelMetadata.FromLambdaExpression(expression, htmlHelper.ViewData);
if (radioHtmlAttributes == null)
radioHtmlAttributes = new RouteValueDictionary();
TagBuilder ulTag = new TagBuilder("ul");
if (!String.IsNullOrEmpty(ulClass))
ulTag.MergeAttribute("class", ulClass);
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);
if (!radioHtmlAttributes.ContainsKey("id"))
radioHtmlAttributes.Add("id", id);
else
radioHtmlAttributes["id"] = id;
// Create and populate a radio button using the existing html helpers
var label = htmlHelper.Label(id, HttpUtility.HtmlEncode(item.Text));
var radio = htmlHelper.RadioButtonFor(expression, item.Value, radioHtmlAttributes).ToHtmlString();
// Create the html string that will be returned to the client
// e.g. <input data-val="true" data-val-required="You must select an option" id="TestRadio_1" name="TestRadio" type="radio" value="1" /><label for="TestRadio_1">Line1</label>
ulTag.InnerHtml += string.Format("<li>{0}{1}</li>", radio, label);
}
}
return MvcHtmlString.Create(ulTag.ToString(TagRenderMode.Normal));
}
public static MvcHtmlString RadioButtonListFor<TModel, TProperty>(
this HtmlHelper<TModel> htmlHelper,
Expression<Func<TModel, TProperty>> expression,
IEnumerable<SelectListItem> listOfValues,
object radioHtmlAttributes = null,
string ulClass = null)
{
return RadioButtonListFor<TModel, TProperty>(htmlHelper, expression, listOfValues, new RouteValueDictionary(radioHtmlAttributes), ulClass);
}
I have implemented something similar in MVC 1.0. See if this will be helpful for you:
public static string RadioButtonList2(this HtmlHelper _helper, string _name, IEnumerable<SelectListItem> _items, string _selectedValue, string _seperator)
{
return RadioButtonList2(_helper, _name, _items, _selectedValue, _seperator, null);
}
public static string RadioButtonList2(this HtmlHelper _helper, string _name, IEnumerable<SelectListItem> _items, string _selectedValue, string _seperator, IDictionary<string, object> _htmlAttributes)
{
StringBuilder _outputScript = new StringBuilder();
foreach (var item in _items)
{
var optionField = new TagBuilder("input");
optionField.MergeAttribute("name", _name);
optionField.MergeAttribute("id", _name);
optionField.MergeAttribute("class", _name);
optionField.MergeAttribute("value", item.Value);
optionField.MergeAttribute("type", "radio");
// Check to see if it's checked
if (item.Value == _selectedValue)
optionField.MergeAttribute("checked", "checked");
if (_htmlAttributes != null)
optionField.MergeAttributes(_htmlAttributes);
_outputScript.Append(optionField.ToString(TagRenderMode.SelfClosing));
_outputScript.Append("<label style=\"display:inline;\">");
_outputScript.Append(item.Text);
_outputScript.Append("</label>" + _seperator);
}
return _outputScript.ToString();
}
In the controller, you can return the result as follows:
ViewData["GenderList"] = new SelectList(new[] { new { Value = "M", Text = "Male" }, new { Value = "F", Text = "Female" }, new { Value = "A", Text = "All" } }, "Value", "Text");
or
ViewData["GenderList"] = new SelectList(_resultFromSomeLinqQuery, "GenderID", "GenderName");
And use it in the View as follows:
<%= Html.RadioButtonList2("Sex", ViewData["GenderList"] as SelectList, ViewData["SelectedSex"].ToString(), " ")%>
You can also replace the with <BR /> to display them in seperate lines.
Hope this helps.
Regards
Naweed Akram
naweed#xgeno.com
Here's a slighly 'slimmer' answer in good ol' VB.
Works for me, but it's not a complete solution.
<Extension()> _
Public Function RadioButtonListFor(Of TModel, TProperty)(ByVal htmlHelper As System.Web.Mvc.HtmlHelper(Of TModel), ByVal expression As System.Linq.Expressions.Expression(Of System.Func(Of TModel, TProperty)), ByVal selectList As System.Collections.Generic.IEnumerable(Of System.Web.Mvc.SelectListItem), ByVal htmlAttributes As Object) As System.Web.Mvc.MvcHtmlString
'Return htmlHelper.DropDownListFor(expression, selectList, htmlAttributes)
If selectList Is Nothing OrElse selectList.Count = 0 Then Return MvcHtmlString.Empty
Dim divTag = New TagBuilder("div")
divTag.MergeAttributes(New RouteValueDictionary(htmlAttributes))
Dim name = CType(expression.Body, System.Linq.Expressions.MemberExpression).Member.Name
Dim value = expression.Compile()(htmlHelper.ViewData.Model)
Dim sb As New StringBuilder()
For Each item In selectList
sb.AppendFormat("<input id=""{0}_{1}"" type=""radio"" name=""{0}"" value=""{1}"" {2} />", name, item.Value, If(item.Value = value.ToString, """checked""", ""))
sb.AppendFormat("<label for=""{0}_{1}"">{2}</label>", name, item.Value, item.Text)
Next
divTag.InnerHtml = sb.ToString
Return MvcHtmlString.Create(divTag.ToString)
End Function
I modified Mac's solution and replaced Enum type by database table, my table is:
In my application I am renting room according Gender preferences.
My model with GenderRadios property:
public partial class Room
{
public RadioButtonListViewModel GenderRadios { get; set; }
//...
}
In room controller, I am preparing Radios:
private void fillRadios(Room room)
{
List<Gender> genders = fre.Genders.ToList();
room.GenderRadios= new RadioButtonListViewModel();
room.GenderRadios.ListItems = new List<RadioButtonListItem>();
foreach (Gender gender in genders)
room.GenderRadios.ListItems.Add(new RadioButtonListItem { Text = gender.Name, Value = gender.Id, Selected= (room.GenderId == gender.Id)});
}
finally, I use it in the view for creating room:
<tr>
<td>Gender</td>
<%= Html.RadioButtonListFor(m => m.GenderRadios, "GenderRadiosForRoomCreate")%>
</tr>
and for editing room:
<tr>
<td>Gender</td>
<%= Html.RadioButtonListFor(m => m.GenderRadios, "GenderRadiosForRoomEdit")%>
</tr>
Create room html will look like:
<td id="GenderRadisoForRoomCreate_Container">
<input id="GenderRadisoForRoomCreate_Any" name="GenderRadisoForRoomCreate_value" value="1" type="radio"><label for="GenderRadisoForRoomCreate_Any">Any</label>
<input id="GenderRadisoForRoomCreate_Female" name="GenderRadisoForRoomCreate_value" value="2" type="radio"><label for="GenderRadisoForRoomCreate_Female">Female</label>
<input id="GenderRadisoForRoomCreate_Male" name="GenderRadisoForRoomCreate_value" value="3" type="radio"><label for="GenderRadisoForRoomCreate_Male">Male</label>
</td>
When room created:
[HttpPost]
public ActionResult RoomCreate(Room room, FormCollection formValues, int? GenderRadiosForRoomCreate_value, int? SmokingRadiosForRoomCreate_value)
{
room.GenderId = GenderRadiosForRoomCreate_value;
room.SmokingId = SmokingRadiosForRoomCreate_value;
//...
}
Here is the helpers class:
public class RadioButtonListViewModel
{
public int Id { get; set; }
private int selectedValue;
public int SelectedValue
{
get { return selectedValue; }
set
{
selectedValue = value;
UpdatedSelectedItems();
}
}
private void UpdatedSelectedItems()
{
if (ListItems == null)
return;
ListItems.ForEach(li => li.Selected = Equals(li.Value, SelectedValue));
}
private List<RadioButtonListItem> listItems;
public List<RadioButtonListItem> ListItems
{
get { return listItems; }
set
{
listItems = value;
UpdatedSelectedItems();
}
}
}
public class RadioButtonListItem
{
public bool Selected { get; set; }
public string Text { get; set; }
public int Value { get; set; }
public override string ToString()
{
return Value.ToString();
}
}
public static class HtmlHelperExtensions
{
/*
tagBase: I used tagBase string for building other tag's Id or Name on this. i.e. for tagBase="GenderRadiosForRoomCreate"
<td id="GenderRadisoForRoomCreate_Container">
<input id="GenderRadisoForRoomCreate_Any" name="GenderRadisoForRoomCreate_value" value="1" type="radio"><label for="GenderRadisoForRoomCreate_Any">Any</label>
<input id="GenderRadisoForRoomCreate_Female" name="GenderRadisoForRoomCreate_value" value="2" type="radio"><label for="GenderRadisoForRoomCreate_Female">Female</label>
<input id="GenderRadisoForRoomCreate_Male" name="GenderRadisoForRoomCreate_value" value="3" type="radio"><label for="GenderRadisoForRoomCreate_Male">Male</label>
</td>
*/
public static string RadioButtonListFor<TModel>(this HtmlHelper<TModel> htmlHelper, Expression<Func<TModel, RadioButtonListViewModel>> expression, String tagBase) where TModel : class
{
return htmlHelper.RadioButtonListFor(expression, tagBase, null);
}
public static string RadioButtonListFor<TModel>(this HtmlHelper<TModel> htmlHelper, Expression<Func<TModel, RadioButtonListViewModel>> expression, String tagBase, object htmlAttributes) where TModel : class
{
return htmlHelper.RadioButtonListFor(expression, tagBase, new RouteValueDictionary(htmlAttributes));
}
public static string RadioButtonListFor<TModel>(this HtmlHelper<TModel> htmlHelper, Expression<Func<TModel, RadioButtonListViewModel>> expression, String tagBase, IDictionary<string, object> htmlAttributes) where TModel : class
{
var inputName = tagBase;
RadioButtonListViewModel radioButtonList = GetValue(htmlHelper, expression);
if (radioButtonList == null)
return String.Empty;
if (radioButtonList.ListItems == null)
return String.Empty;
var containerTag = new TagBuilder("td");
containerTag.MergeAttribute("id", inputName + "_Container");
foreach (var item in radioButtonList.ListItems)
{
var radioButtonTag = RadioButton(htmlHelper, inputName, new SelectListItem{Text=item.Text, Selected = item.Selected, Value = item.Value.ToString()}, htmlAttributes);
containerTag.InnerHtml += radioButtonTag;
}
return containerTag.ToString();
}
public static string RadioButton(this HtmlHelper htmlHelper, string name, SelectListItem listItem,
IDictionary<string, object> htmlAttributes)
{
var inputIdSb = new StringBuilder();
inputIdSb.Append(name);
var sb = new StringBuilder();
var builder = new TagBuilder("input");
if (listItem.Selected) builder.MergeAttribute("checked", "checked");
builder.MergeAttribute("type", "radio");
builder.MergeAttribute("value", listItem.Value);
builder.MergeAttribute("id", inputIdSb.ToString() + "_" + listItem.Text);
builder.MergeAttribute("name", name + "_value");
builder.MergeAttributes(htmlAttributes);
sb.Append(builder.ToString(TagRenderMode.SelfClosing));
sb.Append(RadioButtonLabel(inputIdSb.ToString(), listItem.Text, htmlAttributes));
return sb.ToString();
}
public static string RadioButtonLabel(string inputId, string displayText,
IDictionary<string, object> htmlAttributes)
{
var labelBuilder = new TagBuilder("label");
labelBuilder.MergeAttribute("for", inputId + "_" + displayText);
labelBuilder.MergeAttributes(htmlAttributes);
labelBuilder.InnerHtml = displayText;
return labelBuilder.ToString(TagRenderMode.Normal);
}
public static TProperty GetValue<TModel, TProperty>(HtmlHelper<TModel> htmlHelper, Expression<Func<TModel, TProperty>> expression) where TModel : class
{
TModel model = htmlHelper.ViewData.Model;
if (model == null)
{
return default(TProperty);
}
Func<TModel, TProperty> func = expression.Compile();
return func(model);
}
}