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 { protected readonly HtmlHelper Helper; private readonly string _expressionPrefix; public AngularModelHelper(HtmlHelper helper, string expressionPrefix) { Helper = helper; _expressionPrefix = expressionPrefix; } /// /// Converts an lambda expression into a camel-cased string, prefixed /// with the helper's configured prefix expression, ie: /// vm.model.parentProperty.childProperty /// public IHtmlString ExpressionFor(Expression> property) { var expressionText = ExpressionForInternal(property); return new MvcHtmlString(expressionText); } /// /// Converts a lambda expression into a camel-cased AngularJS binding expression, ie: /// {{vm.model.parentProperty.childProperty}} /// public IHtmlString BindingFor(Expression> property, string filter = "") { return MvcHtmlString.Create("{{" + ExpressionForInternal(property) + (!string.IsNullOrEmpty(filter) ? " | " + filter : string.Empty) + "}}"); } /// /// 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. /// public AngularNgRepeatHelper Repeat( Expression>> property, string variableName) { var propertyExpression = ExpressionForInternal(property); return new AngularNgRepeatHelper( Helper, variableName, propertyExpression); } private string ExpressionForInternal(Expression> property) { var camelCaseName = property.ToCamelCaseName(); var expression = !string.IsNullOrEmpty(_expressionPrefix) ? _expressionPrefix + "." + camelCaseName : camelCaseName; return expression; } public HtmlTag FormGroupFor(Expression> property) { var metadata = ModelMetadata.FromLambdaExpression(property, new ViewDataDictionary()); var name = ExpressionHelper.GetExpressionText(property); var expression = ExpressionForInternal(property); var labelText = metadata.DisplayName ?? name.Humanize(LetterCasing.Title); //Creates var label = new HtmlTag("label") .Attr("for", name) .Text(labelText); var tagName = metadata.DataTypeName == "MultilineText" ? "textarea" : "input"; //Creates 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
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()-]+"); } } }