164 lines
4.5 KiB
C#
164 lines
4.5 KiB
C#
using System;
|
|
using System.Collections.Generic;
|
|
using System.Linq.Expressions;
|
|
using System.Web;
|
|
using System.Web.Mvc;
|
|
using HtmlTags;
|
|
using Humanizer;
|
|
using InventoryTraker.Web.Utilities;
|
|
|
|
namespace InventoryTraker.Web.Helpers
|
|
{
|
|
public class AngularModelHelper<TModel>
|
|
{
|
|
protected readonly HtmlHelper Helper;
|
|
private readonly string _expressionPrefix;
|
|
|
|
public AngularModelHelper(HtmlHelper helper, string expressionPrefix)
|
|
{
|
|
Helper = helper;
|
|
_expressionPrefix = expressionPrefix;
|
|
}
|
|
|
|
/// <summary>
|
|
/// Converts an lambda expression into a camel-cased string, prefixed
|
|
/// with the helper's configured prefix expression, ie:
|
|
/// vm.model.parentProperty.childProperty
|
|
/// </summary>
|
|
public IHtmlString ExpressionFor<TProp>(Expression<Func<TModel, TProp>> property)
|
|
{
|
|
var expressionText = ExpressionForInternal(property);
|
|
return new MvcHtmlString(expressionText);
|
|
}
|
|
|
|
/// <summary>
|
|
/// Converts a lambda expression into a camel-cased AngularJS binding expression, ie:
|
|
/// {{vm.model.parentProperty.childProperty}}
|
|
/// </summary>
|
|
public IHtmlString BindingFor<TProp>(Expression<Func<TModel, TProp>> property, string filter = "")
|
|
{
|
|
return MvcHtmlString.Create("{{"
|
|
+ ExpressionForInternal(property)
|
|
+ (!string.IsNullOrEmpty(filter) ? " | " + filter : string.Empty)
|
|
+ "}}");
|
|
}
|
|
|
|
/// <summary>
|
|
/// Creates a div with an ng-repeat directive to enumerate the specified property,
|
|
/// and returns a new helper you can use for strongly-typed bindings on the items
|
|
/// in the enumerable property.
|
|
/// </summary>
|
|
public AngularNgRepeatHelper<TSubModel> Repeat<TSubModel>(
|
|
Expression<Func<TModel, IEnumerable<TSubModel>>> property, string variableName)
|
|
{
|
|
var propertyExpression = ExpressionForInternal(property);
|
|
return new AngularNgRepeatHelper<TSubModel>(
|
|
Helper, variableName, propertyExpression);
|
|
}
|
|
|
|
private string ExpressionForInternal<TProp>(Expression<Func<TModel, TProp>> property)
|
|
{
|
|
var camelCaseName = property.ToCamelCaseName();
|
|
|
|
var expression = !string.IsNullOrEmpty(_expressionPrefix)
|
|
? _expressionPrefix + "." + camelCaseName
|
|
: camelCaseName;
|
|
|
|
return expression;
|
|
}
|
|
|
|
public HtmlTag FormGroupFor<TProp>(Expression<Func<TModel, TProp>> property)
|
|
{
|
|
var metadata = ModelMetadata.FromLambdaExpression(property, new ViewDataDictionary<TModel>());
|
|
|
|
var name = ExpressionHelper.GetExpressionText(property);
|
|
|
|
var expression = ExpressionForInternal(property);
|
|
|
|
var labelText = metadata.DisplayName ?? name.Humanize(LetterCasing.Title);
|
|
|
|
//Creates <label class="control-label" for="Name">Name</label>
|
|
var label = new HtmlTag("label")
|
|
.Attr("for", name)
|
|
.Text(labelText);
|
|
|
|
var tagName =
|
|
metadata.DataTypeName == "MultilineText"
|
|
? "textarea"
|
|
: "input";
|
|
|
|
//Creates <input ng-model="expression"
|
|
// class="form-control" name="Name" type="text" >
|
|
var input = new HtmlTag(tagName)
|
|
.Attr("ng-model", expression)
|
|
.Attr("name", name);
|
|
|
|
var formGroup = new HtmlTag("div");
|
|
|
|
if (metadata.ModelType != typeof(bool))
|
|
{
|
|
label.AddClass("control-label");
|
|
|
|
var placeholder = metadata.Watermark ??
|
|
labelText + "...";
|
|
|
|
input
|
|
.AddClass("form-control")
|
|
.Attr("type", "text")
|
|
.Attr("placeholder", placeholder);
|
|
|
|
ApplyValidationToInput(input, metadata);
|
|
|
|
//Creates <div class="form-group has-feedback"
|
|
// form-group-validation="Name">
|
|
formGroup
|
|
.AddClass("form-group")
|
|
.AddClass("has-feedback")
|
|
.Attr("form-group-validation", name)
|
|
.Append(label)
|
|
.Append(input);
|
|
}
|
|
else if (metadata.ModelType == typeof(bool))
|
|
{
|
|
label.AddClass("form-check-label");
|
|
|
|
input
|
|
.AddClass("form-check-input")
|
|
.Attr("type", "checkbox");
|
|
|
|
label.Text("")
|
|
.Append(input)
|
|
.AppendHtml(" ")
|
|
.Append(new HtmlTag("text").NoTag().Text(labelText));
|
|
|
|
formGroup
|
|
.AddClass("form-check")
|
|
.Append(label);
|
|
}
|
|
|
|
return formGroup;
|
|
}
|
|
|
|
private void ApplyValidationToInput(HtmlTag input, ModelMetadata metadata)
|
|
{
|
|
if (metadata.IsRequired)
|
|
input.Attr("required", "");
|
|
|
|
if (metadata.DataTypeName == "EmailAddress")
|
|
input.Attr("type", "email");
|
|
|
|
if (metadata.DataTypeName == "Password")
|
|
input.Attr("type", "password");
|
|
|
|
if (metadata.ModelType == typeof(DateTime))
|
|
{
|
|
//input.Attr("type", "date");
|
|
input.Attr("bs-datepicker");
|
|
input.Attr("data-date-format", "M/d/yyyy");
|
|
}
|
|
|
|
if (metadata.DataTypeName == "PhoneNumber")
|
|
input.Attr("pattern", @"[\ 0-9()-]+");
|
|
}
|
|
}
|
|
} |