daveaglick / FluentBootstrap

Provides extensions, helper classes, model binding, and other goodies to help you use the Bootstrap CSS framework from .NET code.
http://www.fluentbootstrap.com
MIT License
200 stars 76 forks source link

Form-group is drawn for ValidationSummary despite there being no validation summary #57

Open wardjc opened 8 years ago

wardjc commented 8 years ago

Hey,

Unsure as to why this is happening but an empty form-group is drawn for the validation summary even when the validation summary is empty.

daveaglick commented 8 years ago

Can you post an example of the form code, what you're seeing, and what you would expect to see? It doesn't have to be complete, just enough so that I know exactly what this issue is about. Thanks!

wardjc commented 8 years ago

Sorry for taking my sweet time (Below is within a partial view hence why no form variable but happens nonetheless):

<div id="user-edit">
    @Bootstrap.ValidationSummary()
    @Bootstrap.EditorFor(m => m.Username)
    @Bootstrap.EditorFor(m => m.Email)
</div>

Renders initially as:

<div id="user-edit">    
   <div class="form-group">
    <div class="col-md-10 col-md-offset-2">
     <div class="form-control-static text-danger"></div>
    </div>
   </div>
   <div class="form-group">
    <label for="Username" class="control-label col-md-2">Username</label>
    <div class="col-md-10">
     <div><input class="text-box single-line form-control" id="Username" name="Username" value="jward@jenison.co.uk" type="text"><span class="field-validation-valid" data-valmsg-for="Username" data-valmsg-replace="true"></span></div>
    </div>
   </div>        
   <div class="form-group">
    <label for="Email" class="control-label col-md-2">Email</label>
    <div class="col-md-10">
     <div><input class="text-box single-line form-control" id="Email" name="Email" value="jward@jenison.co.uk" type="text"><span class="field-validation-valid" data-valmsg-for="Email" data-valmsg-replace="true"></span></div>
    </div>
   </div>
</div>

I'm currently using the following to render the validation summary in a 'Bootstrap style' which i was using previously:

public static MvcHtmlString CustomValidationSummary(this HtmlHelper htmlHelper, bool excludePropertyErrors = false, bool closeable = true)
        {
            IList<string> errorList = new List<string>();

            if (excludePropertyErrors)
            {
                ModelState ms;
                htmlHelper.ViewData.ModelState.TryGetValue(htmlHelper.ViewData.TemplateInfo.HtmlFieldPrefix, out ms);
                if (ms != null)
                    errorList = ms.Errors.Select(e => e.ErrorMessage).ToList();
            }
            else
            {
                var errors = htmlHelper.ViewContext.ViewData.ModelState.SelectMany(state => state.Value.Errors.Select(error => error.ErrorMessage));
                errorList = errors as IList<string> ?? errors.ToList();
            }
            var errorCount = errorList.Count();

            if (errorCount == 0)
            {
                return new MvcHtmlString(string.Empty);
            }

            var div = new TagBuilder("div");
            div.AddCssClass("inspinia-notify"); //Add Inspinia notification style
            div.AddCssClass("alert");
            div.AddCssClass("alert-danger");
            div.Attributes["data-valmsg-summary=true"] = "true";
            string message;

            if (errorCount == 1)
            {
                message = errorList.First();
            }
            else
            {
                message = "Please fix the errors listed below and try again.";
                div.AddCssClass("alert-block");
            }
            if (closeable)
            {
                var button = new TagBuilder("button");
                button.AddCssClass("close");
                button.MergeAttribute("type", "button");
                button.MergeAttribute("data-dismiss", "alert");
                button.InnerHtml = "&times;";
                div.InnerHtml += button.ToString();
            }
            div.InnerHtml += string.Format("<strong>Validation error{0}</strong> {1}", errorCount > 1 ? "s." : ":", message);
            if (errorCount > 1)
            {
                var ul = new TagBuilder("ul");
                foreach (var error in errorList)
                {
                    var li = new TagBuilder("li");
                    li.AddCssClass("text-error");
                    li.SetInnerText(error);
                    ul.InnerHtml += li.ToString();
                }
                div.InnerHtml += ul.ToString();
            }
            return new MvcHtmlString(div.ToString());
        }
daveaglick commented 8 years ago

Sorry, took me a bit to get to this. This behavior is by design, and matches what ASP.NET MVC does without FluentBootstrap. When you call @Html.ValidationSummary() an empty container element is always added to the form, whether or not there is validation content to display. For confirmation, see the screen shot below:

2016-06-15_09h46_46

One of the goals of the FluentBootstrap MVC support is to stick as close to the standard MVC behavior as possible to make swapping it out easier. For example, we don't know if there are other tools in the mix (like a JS script) that looks for this empty div in a particular project. We want those tools to work the same whether the stock MVC validation summary or the FluentBootstrap validation summary is generated.

wardjc commented 8 years ago

Thanks Dave.

The only issue I have is that the generic MVC validation summary does not have padding added to it, whereas your Bootstrap one does due the fact it's wrapped in a form-group. So it's creating an area of empty white-space on the page (more noticeable when it is placed at the top).

Do you have a way around this that you know of? Could we not lose the form-group?

daveaglick commented 8 years ago

Ah, okay. That makes sense. Have you tried:

<div id="user-edit">
    @Bootstrap.ValidationSummary().EnsureFormGroup(false)
    @Bootstrap.EditorFor(m => m.Username)
    @Bootstrap.EditorFor(m => m.Email)
</div>