Skip to content

Commit

Permalink
Improved checking for numbers and undefined values at client side. Sa…
Browse files Browse the repository at this point in the history
…mple extended for enum types support. Tests supplemented.
  • Loading branch information
jwaliszko committed May 15, 2014
1 parent ef90515 commit cbd32db
Show file tree
Hide file tree
Showing 13 changed files with 352 additions and 105 deletions.
5 changes: 0 additions & 5 deletions src/ExpressiveAnnotations.MvcWebSample/Content/Site.css
Original file line number Diff line number Diff line change
Expand Up @@ -117,11 +117,6 @@ input, textarea {
width: 280px;
}

textarea {
font-family: inherit;
width: 500px;
}

input:focus, textarea:focus {
border: 1px solid #7ac0da;
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -7,7 +7,13 @@ public class HomeController : BaseController
{
public ActionResult Index()
{
var model = new Query {SportType = "Extreme", GoAbroad = true};
var model = new Query
{
GoAbroad = true,
Country = "Poland",
NextCountry = "Other",
SportType = "Extreme"
};
return View("Home", model);
}

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -96,10 +96,12 @@
<Compile Include="Global.asax.cs">
<DependentUpon>Global.asax</DependentUpon>
</Compile>
<Compile Include="Misc\Extensions.cs" />
<Compile Include="Misc\ValidationManager.cs" />
<Compile Include="Misc\CultureManager.cs" />
<Compile Include="Models\Contact.cs" />
<Compile Include="Models\Query.cs" />
<Compile Include="Models\Stability.cs" />
<Compile Include="Properties\AssemblyInfo.cs" />
<Compile Include="Resources.Designer.cs">
<AutoGen>True</AutoGen>
Expand Down
47 changes: 47 additions & 0 deletions src/ExpressiveAnnotations.MvcWebSample/Misc/Extensions.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,47 @@
using System;
using System.ComponentModel;
using System.ComponentModel.DataAnnotations;
using System.Globalization;
using System.Linq;
using System.Linq.Expressions;
using System.Web.Mvc;
using System.Web.Mvc.Html;

namespace ExpressiveAnnotations.MvcWebSample.Misc
{
public static class Extensions
{
public static MvcHtmlString EnumDropDownListFor<TModel, TEnum>(this HtmlHelper<TModel> htmlHelper, Expression<Func<TModel, TEnum>> expression)
{
return EnumDropDownListFor(htmlHelper, expression, null);
}

public static MvcHtmlString EnumDropDownListFor<TModel, TEnum>(this HtmlHelper<TModel> htmlHelper, Expression<Func<TModel, TEnum>> expression, object htmlAttributes)
{
var metadata = ModelMetadata.FromLambdaExpression(expression, htmlHelper.ViewData);
var type = Nullable.GetUnderlyingType(metadata.ModelType) ?? metadata.ModelType;
if (!type.IsEnum)
throw new ArgumentException("Given parameter expression has to indicate enum type.", "expression");
var values = Enum.GetValues(type).Cast<TEnum>();

var items = values.Select(value => new SelectListItem
{
Text = GetEnumDisplayText(value),
Value = Convert.ToInt32(value).ToString(CultureInfo.InvariantCulture),
Selected = value.Equals(metadata.Model)
});

if (metadata.IsNullableValueType) // if the enum is nullable, add an empty item to the collection
items = new[] {new SelectListItem()}.Concat(items);

return htmlHelper.DropDownListFor(expression, items, htmlAttributes);
}

private static string GetEnumDisplayText<TEnum>(TEnum value)
{
var field = value.GetType().GetField(value.ToString());
var attrib = field.GetCustomAttributes(typeof(DisplayAttribute), false).FirstOrDefault() as DisplayAttribute;
return attrib != null ? attrib.GetName() : value.ToString();
}
}
}
87 changes: 53 additions & 34 deletions src/ExpressiveAnnotations.MvcWebSample/Models/Query.cs
Original file line number Diff line number Diff line change
Expand Up @@ -13,11 +13,11 @@ public IEnumerable<SelectListItem> Sports
get
{
return new[]
{
new SelectListItem {Text = Resources.None, Value = "None"},
new SelectListItem {Text = Resources.Normal, Value = "Normal"},
new SelectListItem {Text = Resources.Extreme, Value = "Extreme"}
};
{
new SelectListItem {Text = Resources.None, Value = "None"},
new SelectListItem {Text = Resources.Normal, Value = "Normal"},
new SelectListItem {Text = Resources.Extreme, Value = "Extreme"}
};
}
}

Expand All @@ -26,12 +26,12 @@ public IEnumerable<SelectListItem> Countries
get
{
return new[]
{
new SelectListItem {Text = Resources.Poland, Value = "Poland"},
new SelectListItem {Text = Resources.Germany, Value = "Germany"},
new SelectListItem {Text = Resources.France, Value = "France"},
new SelectListItem {Text = Resources.Other, Value = "Other"}
};
{
new SelectListItem {Text = Resources.Poland, Value = "Poland"},
new SelectListItem {Text = Resources.Germany, Value = "Germany"},
new SelectListItem {Text = Resources.France, Value = "France"},
new SelectListItem {Text = Resources.Other, Value = "Other"}
};
}
}

Expand All @@ -40,53 +40,72 @@ public IEnumerable<int?> Years
get { return new int?[] {null}.Concat(Enumerable.Range(18, 73).Select(x => (int?) x)); }
}

[Display(ResourceType = typeof(Resources), Name = "GoAbroad")]
[Display(ResourceType = typeof (Resources), Name = "GoAbroad")]
public bool GoAbroad { get; set; }

[Required(ErrorMessageResourceType = typeof(Resources), ErrorMessageResourceName = "AgeRequired")]
[Display(ResourceType = typeof(Resources), Name = "Age")]
[Required(ErrorMessageResourceType = typeof (Resources), ErrorMessageResourceName = "FieldRequired")]
[Display(ResourceType = typeof (Resources), Name = "Age")]
public int? Age { get; set; }

[RequiredIf(DependentProperty = "GoAbroad", TargetValue = true, ErrorMessageResourceType = typeof(Resources), ErrorMessageResourceName = "FieldRequired")]
[Display(ResourceType = typeof(Resources), Name = "PassportNumber")]

[RequiredIf(
DependentProperty = "GoAbroad",
TargetValue = true,
ErrorMessageResourceType = typeof (Resources), ErrorMessageResourceName = "FieldConditionallyRequired")]
[Display(ResourceType = typeof (Resources), Name = "PassportNumber")]
public string PassportNumber { get; set; }

[Display(ResourceType = typeof(Resources), Name = "Country")]
[Display(ResourceType = typeof (Resources), Name = "Country")]
public string Country { get; set; }

[Display(ResourceType = typeof(Resources), Name = "NextCountry")]
[Display(ResourceType = typeof (Resources), Name = "NextCountry")]
public string NextCountry { get; set; }

[RequiredIfExpression( /* interpretation => GoAbroad == true
* && ( (NextCountry != "Other" && NextCountry == [value from Country])
* || Age ∈ (24, 55>
* )
*/
[RequiredIfExpression( /* interpretation => GoAbroad == true
* && ( (NextCountry != "Other" && NextCountry == [value from Country])
* || Age ∈ (24, 55>
* )
*/
Expression = "{0} && ( (!{1} && {2}) || ({3} && {4}) )",
DependentProperties = new[] {"GoAbroad", "NextCountry", "NextCountry", "Age", "Age"},
RelationalOperators = new[] {"==", "==", "==", ">", "<="},
TargetValues = new object[] {true, "Other", "[Country]", 24, 55},
ErrorMessageResourceType = typeof (Resources), ErrorMessageResourceName = "ReasonForTravelRequired")]
[Display(ResourceType = typeof(Resources), Name = "ReasonForTravel")]
[Display(ResourceType = typeof (Resources), Name = "ReasonForTravel")]
public string ReasonForTravel { get; set; }

[Display(ResourceType = typeof(Resources), Name = "SportType")]
[Display(ResourceType = typeof (Resources), Name = "PoliticalStability")]
[RequiredIf(
DependentProperty = "GoAbroad",
RelationalOperator = "!=",
TargetValue = false,
ErrorMessageResourceType = typeof (Resources), ErrorMessageResourceName = "FieldConditionallyRequired")]
public Stability? PoliticalStability { get; set; }

[RequiredIfExpression( /* interpretation => PoliticalStability != null && PoliticalStability != Stability.High */
Expression = "!{0} && !{1}",
DependentProperties = new[] {"PoliticalStability", "PoliticalStability"},
TargetValues = new object[] {null, Stability.High},
ErrorMessageResourceType = typeof (Resources), ErrorMessageResourceName = "AwareOfTheRisksRequired")]
[Display(ResourceType = typeof (Resources), Name = "AwareOfTheRisks")]
public bool AwareOfTheRisks { get; set; }

[Display(ResourceType = typeof (Resources), Name = "SportType")]
public string SportType { get; set; }

[RequiredIfExpression( /* interpretation => SportType == "Extreme" || (SportType != "None" && GoAbroad == true) */
[RequiredIfExpression( /* interpretation => SportType == "Extreme" || (SportType != "None" && GoAbroad == true) */
Expression = "{0} || (!{1} && {2})",
DependentProperties = new[] {"SportType", "SportType", "GoAbroad"},
TargetValues = new object[] {"Extreme", "None", true},
ErrorMessageResourceType = typeof(Resources), ErrorMessageResourceName = "BloodTypeRequired")]
[Display(ResourceType = typeof(Resources), Name = "BloodType")]
ErrorMessageResourceType = typeof (Resources), ErrorMessageResourceName = "BloodTypeRequired")]
[Display(ResourceType = typeof (Resources), Name = "BloodType")]
public string BloodType { get; set; }

[RequiredIfExpression(
[RequiredIfExpression( /* interpretation => ContactDetails.Email == "*" || ContactDetails.Phone == "*" */
Expression = "{0} || {1}",
DependentProperties = new[] { "ContactDetails.Email", "ContactDetails.Phone" }, /* nested properties are supported */
TargetValues = new object[] { "*", "*" }, /* any values */
ErrorMessageResourceType = typeof(Resources), ErrorMessageResourceName = "AgreeForContactRequired")]
[Display(ResourceType = typeof(Resources), Name = "AgreeForContact")]
DependentProperties = new[] {"ContactDetails.Email", "ContactDetails.Phone"}, /* nested properties are supported */
TargetValues = new object[] {"*", "*"}, /* any values */
ErrorMessageResourceType = typeof (Resources), ErrorMessageResourceName = "AgreeForContactRequired")]
[Display(ResourceType = typeof (Resources), Name = "AgreeForContact")]
public bool AgreeForContact { get; set; }

public Contact ContactDetails { get; set; }
Expand Down
14 changes: 14 additions & 0 deletions src/ExpressiveAnnotations.MvcWebSample/Models/Stability.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,14 @@
using System.ComponentModel.DataAnnotations;

namespace ExpressiveAnnotations.MvcWebSample.Models
{
public enum Stability
{
[Display(ResourceType = typeof(Resources), Name = "High")]
High,
[Display(ResourceType = typeof(Resources), Name = "Low")]
Low,
[Display(ResourceType = typeof(Resources), Name = "Uncertain")]
Uncertain,
}
}
78 changes: 66 additions & 12 deletions src/ExpressiveAnnotations.MvcWebSample/Resources.Designer.cs

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

Loading

0 comments on commit cbd32db

Please sign in to comment.