M E Moriarty
M E Moriarty

Reputation: 231

Custom validation error message location

I've been struggling with how to change the following to fit my needs. This is for a form I have with simple inputs. The way the code is now it simply displays a label, the field and a validation message vertically, but I want to make it horizontal (using a <table>).

Currently I have this code:

var wrapper = new TagBuilder("div");
wrapper.AddCssClass("field-wrapper");

var table = new TagBuilder("table");//This is my test to insert a table

var label = new TagBuilder("div");
label.AddCssClass("field-label");
if (metadata.IsRequired && !metadata.IsReadOnly)
    {
        if (metadata.ModelType != typeof (bool))
        {
            label.InnerHtml += "* ";
            wrapper.AddCssClass("required");
        }
    }

label.InnerHtml += html.LabelFor(expression);
wrapper.InnerHtml += label;

var input = new TagBuilder("div");
input.AddCssClass("field-input");
input.InnerHtml += html.EditorFor(expression);

if (!string.IsNullOrEmpty(metadata.Description))
    {
        input.InnerHtml += html.TooltipFor(expression);//declared elsewhere to show a tooltip
    }

input.InnerHtml += html.ValidationMessageFor(expression);

wrapper.InnerHtml += input;
wrapper.InnerHtml += table;//This is my test to insert a table
return MvcHtmlString.Create(wrapper + "\r\n");

I tried inserting a <table> but this is the structure of the HTML with that code:

<div class="field-wrapper">
    <div class="field-label"> 
        <label for="Name">Name</label>
    </div>
    <div class="field-input">
        * <input class="text-box single-line input-validation-error" data-val="true" data-val-required="The Name field is required." id="Name" name="Name" type="text" value="">
        <!--tooltip would ordinarily show up here-->
        <span class="field-validation-error" data-valmsg-for="Name" data-valmsg-replace="true">
            <span for="Name" generated="true" class="">The Name field is required.</span>
        </span>
    </div>
    <table></table><!--This is my table-->
</div>

This is what it looks like after validation-error:

enter image description here

What I am going for is this structure:

<div class="field-wrapper">
    <table border="0">
        <tbody>
            <tr>
                <td width="40%">
                    <div class="field-label">
                        <label class="mylabelstyle" for="FirstName" title="Enter first name.">First Name:</label>
                    </div>
                 </td>
                 <td width="60%">
                     <div class="field-input">
                         <input data-val="true" data-val-required="First Name required." id="FirstName" name="FirstName" type="text" value="" />
                         <!--tooltip here as necessary-->
                         <span class="field-validation-valid" data-valmsg-for="FirstName" data-valmsg-replace="true"></span>
                     </div>
                 </td>
              </tr>
          </tbody>
    </table>
</div>

Visually, this is what I am after:

enter image description here

A couple of things to note:

  1. The "*" (required code) and tooltip are shown under certain conditions.
  2. Styling will not be a problem - I am focused on structure here.
  3. I used different helpers for the inputs, so the code inside each (and the name, i.e., Name v. FirstName) is different and not the problem.
  4. The <table> is inside a <div> that's floated left. I have some static content on the right which is not the problem (it shows up under the validation in the second image), so that's also not important.

I am not good with the TagBuilder and have just been making a mess of everything. Any help is greatly appreciated. Thanks!

Upvotes: 0

Views: 3463

Answers (1)

Darin Dimitrov
Darin Dimitrov

Reputation: 1039268

There you go:

public static IHtmlString MyEditorFor<TModel, TProperty>(
    this HtmlHelper<TModel> html, 
    Expression<Func<TModel, TProperty>> expression
)
{
    var metadata = ModelMetadata.FromLambdaExpression<TModel, TProperty>(expression, html.ViewData);

    var wrapper = new TagBuilder("div");
    wrapper.AddCssClass("field-wrapper");
    var table = new TagBuilder("table");
    table.Attributes["border"] = "0";
    var tbody = new TagBuilder("tbody");
    var tr = new TagBuilder("tr");
    var td1 = new TagBuilder("td");
    td1.Attributes["width"] = "40%";
    var label = new TagBuilder("div");
    label.AddCssClass("field-label");
    if (metadata.IsRequired && !metadata.IsReadOnly)
    {
        if (metadata.ModelType != typeof(bool))
        {
            label.InnerHtml += "* ";
            wrapper.AddCssClass("required");
        }
    }
    label.InnerHtml += html.LabelFor(expression);
    td1.InnerHtml = label.ToString();
    var td2 = new TagBuilder("td");
    td2.Attributes["width"] = "60%";
    var input = new TagBuilder("div");
    input.AddCssClass("field-input");
    input.InnerHtml += html.EditorFor(expression);

    if (!string.IsNullOrEmpty(metadata.Description))
    {
        input.InnerHtml += html.TooltipFor(expression);
    }
    input.InnerHtml += html.ValidationMessageFor(expression);
    td2.InnerHtml = input.ToString();
    tr.InnerHtml = td1.ToString() + td2.ToString();
    tbody.InnerHtml = tr.ToString();
    table.InnerHtml = tbody.ToString();
    wrapper.InnerHtml = table.ToString();
    return new HtmlString(wrapper + Environment.NewLine);
}

Upvotes: 2

Related Questions