public static HtmlString ngDropDownListFor <TModel, TProperty, TDisplayProperty>(this IHtmlHelper <TModel> html, Expression <Func <TModel, TProperty> > propertyExpression, Expression <Func <TModel, TDisplayProperty> > displayExpression, string source, string nullOption, IDictionary <string, object> htmlAttributes)
        {
            var helper = html as AngularHtmlHelper <TModel>;

            if (helper == null)
            {
                throw new InvalidOperationException("You need to configure the services container to return AngularHtmlHelper<T> for IHtmlHelper<T>.");
            }

            var propertyExpressionText = ExpressionHelper.GetExpressionText(propertyExpression);
            var displayExpressionText  = ExpressionHelper.GetExpressionText(displayExpression);
            var metadata = ExpressionMetadataProvider.FromLambdaExpression(propertyExpression, helper.ViewData, helper.ModelMetadataProvider);
            var tag      = new TagBuilder("select");

            var valueFieldName   = html.ViewData.TemplateInfo.GetFullHtmlFieldName(propertyExpressionText);
            var displayFieldName = html.ViewData.TemplateInfo.GetFullHtmlFieldName(displayExpressionText);

            var displayFieldNameParts = displayFieldName.Split('.');

            displayFieldName = displayFieldNameParts[displayFieldNameParts.Length - 1];

            tag.Attributes["id"]       = helper.GetFullHtmlFieldId(propertyExpressionText).ToString();
            tag.Attributes["name"]     = valueFieldName;
            tag.Attributes["ng-model"] = valueFieldName;

            var ngOptionsFormat = "a.{0} as a.{1} for a in {2}";
            var ngOptions       = string.Format(ngOptionsFormat, valueFieldName, displayFieldName, source);

            tag.Attributes["ng-options"] = ngOptions;

            if (nullOption != null)
            {
                var nullOptionTag = new TagBuilder("option");
                nullOptionTag.Attributes["value"] = string.Empty;
                nullOptionTag.SetInnerText(nullOption);
                tag.InnerHtml = nullOptionTag.ToString();
            }

            var clientValidators = helper.GetClientValidators(null, metadata);
            var isRequired       = clientValidators.SingleOrDefault(cv => string.Equals(cv.ValidationType, "required", StringComparison.OrdinalIgnoreCase)) != null;

            if (isRequired)
            {
                tag.Attributes["required"] = string.Empty;
            }

            tag.MergeAttributes(htmlAttributes, replaceExisting: true);

            return(tag.ToHtmlString(TagRenderMode.Normal));
        }
Exemple #2
0
        public static HtmlString ngTextBoxFor <TModel, TProperty>(this IHtmlHelper <TModel> html, Expression <Func <TModel, TProperty> > expression, IDictionary <string, object> htmlAttributes)
        {
            var expressionText = ExpressionHelper.GetExpressionText(expression);
            var metadata       = ExpressionMetadataProvider.FromLambdaExpression(expression, html.ViewData, html.MetadataProvider);
            var ngAttributes   = new Dictionary <string, object>();

            ngAttributes["type"] = "text";

            // Angular binding to client-side model (scope). This is required for Angular validation to work.
            var valueFieldName = html.ViewData.TemplateInfo.GetFullHtmlFieldName(expressionText);

            ngAttributes["name"]     = valueFieldName;
            ngAttributes["ng-model"] = valueFieldName;

            // Set input type
            if (string.Equals(metadata.DataTypeName, Enum.GetName(typeof(DataType), DataType.EmailAddress), StringComparison.OrdinalIgnoreCase))
            {
                ngAttributes["type"] = "email";
            }
            else if (metadata.ModelType == typeof(Uri) ||
                     string.Equals(metadata.DataTypeName, Enum.GetName(typeof(DataType), DataType.Url), StringComparison.OrdinalIgnoreCase) ||
                     string.Equals(metadata.DataTypeName, Enum.GetName(typeof(DataType), DataType.ImageUrl), StringComparison.OrdinalIgnoreCase))
            {
                ngAttributes["type"] = "url";
            }
            else if (IsNumberType(metadata.ModelType))
            {
                ngAttributes["type"] = "number";
                if (IsIntegerType(metadata.ModelType))
                {
                    ngAttributes["step"] = "1";
                }
                else
                {
                    ngAttributes["step"] = "any";
                }
            }
            else if (metadata.ModelType == typeof(DateTime))
            {
                if (string.Equals(metadata.DataTypeName, Enum.GetName(typeof(DataType), DataType.Date), StringComparison.OrdinalIgnoreCase))
                {
                    ngAttributes["type"] = "date";
                }
                else if (string.Equals(metadata.DataTypeName, Enum.GetName(typeof(DataType), DataType.DateTime), StringComparison.OrdinalIgnoreCase))
                {
                    ngAttributes["type"] = "datetime";
                }
            }

            // Add attributes for Angular validation
            var clientValidators = html.GetClientValidationRules(metadata, null);

            foreach (var validator in clientValidators)
            {
                if (string.Equals(validator.ValidationType, "length"))
                {
                    if (validator.ValidationParameters.ContainsKey("min"))
                    {
                        ngAttributes["ng-minlength"] = validator.ValidationParameters["min"];
                    }
                    if (validator.ValidationParameters.ContainsKey("max"))
                    {
                        ngAttributes["ng-maxlength"] = validator.ValidationParameters["max"];
                    }
                }
                else if (string.Equals(validator.ValidationType, "required"))
                {
                    ngAttributes["required"] = null;
                }
                else if (string.Equals(validator.ValidationType, "range"))
                {
                    if (validator.ValidationParameters.ContainsKey("min"))
                    {
                        ngAttributes["min"] = validator.ValidationParameters["min"];
                    }
                    if (validator.ValidationParameters.ContainsKey("max"))
                    {
                        ngAttributes["max"] = validator.ValidationParameters["max"];
                    }
                }
                else if (string.Equals(validator.ValidationType, "equalto"))
                {
                    // CompareAttribute validator
                    var fieldToCompare = validator.ValidationParameters["other"]; // e.g. *.NewPassword
                    var other          = validator.ValidationParameters["other"].ToString();
                    if (other.StartsWith("*."))
                    {
                        // The built-in CompareAttributeAdapter prepends *. to the property name so we strip it off here
                        other = other.Substring("*.".Length);
                    }
                    ngAttributes["app-equal-to"] = other;
                    // TODO: Actually write the Angular directive to use this
                }
                // TODO: Regex, Phone(regex)
            }

            // Render!
            if (metadata.Model != null)
            {
                ngAttributes.Add("value", metadata.Model.ToString());
            }

            var tag = new TagBuilder("input");

            tag.MergeAttributes(MergeAttributes(ngAttributes, htmlAttributes));
            return(tag.ToHtmlString(TagRenderMode.SelfClosing));
        }