tags:

views:

949

answers:

3

Interesting situation. I have a Html.Textbox() that I render from a view as follows:

<%= Html.TextBox("title", Model.Title, new { @class = "txt" }) %>

In my controller, I have the following, somewhat simplified, validation on the title. For arguments sake, assume it finds the error, and re-renders the view with the modelstate error information.

[AcceptVerbs(HttpVerbs.Post)]
public ActionResult EditBook(string title) {
    Model = new Book(ControllerContext.RequestContext);
    if (String.IsNullOrEmpty(title))
    {
        title = String.Empty;
        ModelState.AddModelError("title", "* Title is a required");
        modelState.SetModelValue("title", ValueProvider["title"]);
    }
    else { // show confirmation }

    if (!ModelState.IsValid)
    {
        return View("EditBook", Model);
    }
}

When the page is re-rendered, my html text box correctly has the input-validation-error class attached to it... But it's useless as it's the first class attached! I need it to override all existing styles on my text box. The html output is as follows:

<input type="text" name="title" id="title" class="input-validation-error txt"/>

Assume the following css styles have been defined:

input.txt { border: 1px; color: #000 }
.input-validation-error { border: 2px solid #fff }

The problem is, my original css class "txt" takes precedence, and prevents me from being able to style the error text box correctly.

Any thoughts?

+3  A: 

This is more a CSS question than ASP.NET MVC specific. You should look at the Cascading order section of the CSS spec.

With that in mind, you can change the precedence of your styles by tweaking it as follows:

input.txt { border: 1px; color: #000 }
input.input-validation-error { border: 2px solid #fff }

With the addition of the input element to the input-validation-error class, the specificity of the two styles would be the same. This will cause the styles' declaration order to be used to determine precedence (in that case the spec says that last one declared wins).

Note the example above is just one way you can control the precedence... there may be a better way, but I'm not a CSS expert. You might get a better/more insightful response if you re-ask as a CSS question with CSS tags.

PS. The order in which the class names are declared on the element is irrelevant when determining precedence.

DSO
Remember you can have more than one selector for a CSS rule: `input.input-validation-error, .input-validation-error { border: 2px solid #fff }` so you don't lose the style on non-<input> elements with class input-validation-error.
Jacob
+1  A: 

If you add the !important modifier it should help with this problem.

.input-validation-error { border: 2px solid #fff !important; }

Also, modifying what @DSO said a bit, I'm pretty sure you could also try this:

input.txt { border: 1px; color: #000 }
input.txt.input-validation-error { border: 2px solid #fff }

Like I said, I'm pretty sure you can do that if you have something with two CSS classes.

dhulk
Be aware that the multiple class selector (input.txt.input-validation-error) is buggy in IE6 - see http://www.quirksmode.org/css/multipleclasses.html
Alconja
Ah, didn't know that, thanks. I would just try the !important tag in light of this info.
dhulk
A: 

Instead of relying on the framework to render styles at all, I went with an approach where I could apply my own css classes, while still using much of the Html.ValidationMessage() infrastructure.

Looks something like this:

<% bool emailError = !String.IsNullOrEmpty(Html.ValidationMessage("email"));  %>
<div id="EmailMod" class="module <%= emailError ? "error" : String.Empty %>">
    <label class="text_right">Email address</label>
    <div class="input">
        <input type="text" id="Email" name="Email" class="input" tabindex="1" />
        <p id="EmailRequired" class="required <%= emailError ? "" : "hide" %>">* Please enter a valid email address.</p>
    </div>
</div>
Kevin