protected internal virtual void AddCommonFormFieldAttributes(IFormField formField, HtmlElementWriter formControl)
        {
            var typeName = formField.TypeName;

            if (IsEnum(formField) || IsDate(formField))
            {
                typeName = StringFormType.TypeName;
            }

            typeName = typeName.Substring(0, 1).ToUpper() + typeName.Substring(1);

            var formFieldId = formField.Id;

            formControl.Attribute(ClassAttribute, FormControlClass)
            .Attribute(NameAttribute, formFieldId)
            .Attribute(CamVariableTypeAttribute, typeName)
            .Attribute(CamVariableNameAttribute, formFieldId);

            // add validation constraints
            foreach (var constraint in formField.ValidationConstraints)
            {
                var constraintName = constraint.Name;
                var configuration  = (string)constraint.Configuration;
                formControl.Attribute(constraintName, configuration);
            }
        }
        protected internal virtual void RenderInvalidDateMessage(IFormField formField,
                                                                 HtmlDocumentBuilder documentBuilder)
        {
            var formFieldId = formField.Id;

            var firstDivElement = new HtmlElementWriter(DivElement);

            var firstExpression = string.Format(RequiredErrorExpression + " && !" + DateErrorExpression,
                                                formFieldId, formFieldId);

            firstDivElement.Attribute(NgShowAttribute, firstExpression)
            .Attribute(ClassAttribute, HelpBlockClass)
            .TextContent(RequiredFieldMessage);

            documentBuilder.StartElement(firstDivElement).EndElement();

            var secondDivElement = new HtmlElementWriter(DivElement);

            var secondExpression = string.Format(DateErrorExpression, formFieldId);

            secondDivElement.Attribute(NgShowAttribute, secondExpression)
            .Attribute(ClassAttribute, HelpBlockClass)
            .TextContent(InvalidDateFieldMessage);

            documentBuilder.StartElement(secondDivElement).EndElement();
        }
        protected internal virtual void RenderInvalidMessageElement(IFormField formField,
                                                                    HtmlDocumentBuilder documentBuilder)
        {
            var divElement = new HtmlElementWriter(DivElement);

            var formFieldId  = formField.Id;
            var ifExpression = string.Format(InvalidExpression + " && " + DirtyExpression, formFieldId, formFieldId);

            divElement.Attribute(NgIfAttribute, ifExpression).Attribute(ClassAttribute, HasErrorClass);

            // <div ng-if="....$invalid && ....$dirty"...>
            documentBuilder.StartElement(divElement);

            if (!IsDate(formField))
            {
                RenderInvalidValueMessage(formField, documentBuilder);
                RenderInvalidTypeMessage(formField, documentBuilder);
            }
            else
            {
                RenderInvalidDateMessage(formField, documentBuilder);
            }

            documentBuilder.EndElement();
        }
        protected internal virtual HtmlElementWriter CreateInputField(IFormField formField)
        {
            var inputField = new HtmlElementWriter(InputElement, true);

            AddCommonFormFieldAttributes(formField, inputField);

            inputField.Attribute(TypeAttribute, TextInputType);

            return(inputField);
        }
        protected internal virtual void RenderInputField(IFormField formField, HtmlDocumentBuilder documentBuilder)
        {
            var inputField = new HtmlElementWriter(InputElement, true);

            AddCommonFormFieldAttributes(formField, inputField);

            var inputType = !IsBoolean(formField) ? TextInputType : CheckboxInputType;

            inputField.Attribute(TypeAttribute, inputType);

            // add default value
            var defaultValue = formField.DefaultValue;

            if (defaultValue != null)
            {
                inputField.Attribute(ValueAttribute, defaultValue.ToString());
            }

            // <input ... />
            documentBuilder.StartElement(inputField).EndElement();
        }
        protected internal virtual void RenderInvalidValueMessage(IFormField formField,
                                                                  HtmlDocumentBuilder documentBuilder)
        {
            var divElement = new HtmlElementWriter(DivElement);

            var formFieldId = formField.Id;

            var expression = string.Format(RequiredErrorExpression, formFieldId);

            divElement.Attribute(NgShowAttribute, expression)
            .Attribute(ClassAttribute, HelpBlockClass)
            .TextContent(RequiredFieldMessage);

            documentBuilder.StartElement(divElement).EndElement();
        }
        protected internal virtual void RenderInvalidTypeMessage(IFormField formField,
                                                                 HtmlDocumentBuilder documentBuilder)
        {
            var divElement = new HtmlElementWriter(DivElement);

            var formFieldId = formField.Id;

            var expression = string.Format(TypeErrorExpression, formFieldId);

            var typeName = formField.TypeName;

            if (IsEnum(formField))
            {
                typeName = StringFormType.TypeName;
            }

            divElement.Attribute(NgShowAttribute, expression)
            .Attribute(ClassAttribute, HelpBlockClass)
            .TextContent(string.Format(TypeFieldMessage, typeName));

            documentBuilder.StartElement(divElement).EndElement();
        }