16

I'm testing a list of things for null. Every time I find one, I save it in an array to implement it in a validationmessage.

Output I want looks like this:

Field 1 is required
Field 4 is required
etc...

But I can't seem to be able to start a new line.

Now, it looks like this:

Field 1 is required Field 4 is required

Does anybody know how to achieve this?

EDIT:

controller:

IDictionary<int, String> emptyFields = new Dictionary<int, String>();

foreach (Something thing in AnotherThing.Collection)
{
    if (thing.Property == null)
        emptyFields.add(thing.Index, thing.Name);                   
}

if (emptyFields.Any())
    throw new CustomException() { EmptyFields = emptyFields };

This exception is handled here:

catch (CustomException ex)
{                   
    ModelState.AddModelError("file", ex.GetExceptionString());
    return View("theView");
}    

CustomException:

public class CustomException: Exception
{
    public IDictionary<int,String> EmptyFields { get; set; }
    public override String Label { get { return "someLabel"; } }
    public override String GetExceptionString()
    {
        String msg = "";
        foreach (KeyValuePair<int,String> elem in EmptyFields)
        {
            msg += "row: " + (elem.Key + 1).ToString() + " column: " + elem.Value + "<br/>";      
        }
        return msg;        
    }
}

view:

<span style="color: #FF0000">@Html.Raw(Html.ValidationMessage("file").ToString())</span>
Ciarán Bruen
  • 5,221
  • 13
  • 59
  • 69
sander
  • 719
  • 2
  • 9
  • 21

7 Answers7

19

You can do it with this one liner:

@Html.Raw(HttpUtility.HtmlDecode(Html.ValidationMessageFor(m => m.Property).ToHtmlString()))
Leniel Maccaferri
  • 100,159
  • 46
  • 371
  • 480
  • 6
    +1 Smart, this the perfect for a simple and short fix that I and the author was looking for. – Alex Jun 06 '14 at 07:10
  • 2
    I have used it for validation summary like this @if (Html.ValidationSummary(true) != null) { @Html.Raw(HttpUtility.HtmlDecode(Html.ValidationSummary(true).ToString())); } – Yasmine Jan 12 '15 at 10:07
  • 2
    +1 This should be the right answer! I agree with @sander no one wants to add 50 lines of code for just having a line break! – Buka Nov 03 '17 at 11:25
8

You will need to write a custom helper to achieve that. The built-in ValidationMessageFor helper automatically HTML encodes the value. Here's an example:

public static class ValidationMessageExtensions
{
    public static IHtmlString MyValidationMessageFor<TModel, TProperty>(
        this HtmlHelper<TModel> htmlHelper, 
        Expression<Func<TModel, TProperty>> ex
    )
    {
        var htmlAttributes = new RouteValueDictionary();
        string validationMessage = null;
        var expression = ExpressionHelper.GetExpressionText(ex);
        var modelName = htmlHelper.ViewContext.ViewData.TemplateInfo.GetFullHtmlFieldName(expression);
        var formContext = htmlHelper.ViewContext.ClientValidationEnabled ? htmlHelper.ViewContext.FormContext : null;
        if (!htmlHelper.ViewData.ModelState.ContainsKey(modelName) && formContext == null)
        {
            return null;
        }

        var modelState = htmlHelper.ViewData.ModelState[modelName];
        var modelErrors = (modelState == null) ? null : modelState.Errors;
        var modelError = (((modelErrors == null) || (modelErrors.Count == 0)) 
            ? null 
            : modelErrors.FirstOrDefault(m => !String.IsNullOrEmpty(m.ErrorMessage)) ?? modelErrors[0]);

        if (modelError == null && formContext == null)
        {
            return null;
        }

        var builder = new TagBuilder("span");
        builder.MergeAttributes(htmlAttributes);
        builder.AddCssClass((modelError != null) ? HtmlHelper.ValidationMessageCssClassName : HtmlHelper.ValidationMessageValidCssClassName);

        if (!String.IsNullOrEmpty(validationMessage))
        {
            builder.InnerHtml = validationMessage;
        }
        else if (modelError != null)
        {
            builder.InnerHtml = GetUserErrorMessageOrDefault(htmlHelper.ViewContext.HttpContext, modelError, modelState);
        }

        if (formContext != null)
        {
            bool replaceValidationMessageContents = String.IsNullOrEmpty(validationMessage);
            builder.MergeAttribute("data-valmsg-for", modelName);
            builder.MergeAttribute("data-valmsg-replace", replaceValidationMessageContents.ToString().ToLowerInvariant());
        }

        return new HtmlString(builder.ToString(TagRenderMode.Normal));
    }

    private static string GetUserErrorMessageOrDefault(HttpContextBase httpContext, ModelError error, ModelState modelState)
    {
        if (!String.IsNullOrEmpty(error.ErrorMessage))
        {
            return error.ErrorMessage;
        }
        if (modelState == null)
        {
            return null;
        }

        var attemptedValue = (modelState.Value != null) ? modelState.Value.AttemptedValue : null;
        return string.Format(CultureInfo.CurrentCulture, "Value '{0}' not valid for property", attemptedValue);
    }
}

and then:

public class MyViewModel
{
    [Required(ErrorMessage = "Error Line1<br/>Error Line2")]
    public string SomeProperty { get; set; }
}

and in the view:

@model MyViewModel
@using (Html.BeginForm())
{
    @Html.EditorFor(x => x.SomeProperty)
    @Html.MyValidationMessageFor(x => x.SomeProperty)
    <button type="submit">OK</button>
}

And if you want to display the error message in a ValidationSummary you could also write a custom helper that will not HTML encode the error message as I have shown in this post.

Community
  • 1
  • 1
Darin Dimitrov
  • 1,023,142
  • 271
  • 3,287
  • 2,928
  • 4
    I have found some threads regarding an extension. But it felt like an aweful lot of work to achieve something so basic. I just wanted to check if I there was another way. – sander Oct 16 '12 at 07:59
  • 1
    You call 50 lines of code awful lot of work? Wow. How do you even manage to write real code then :-) – Darin Dimitrov Oct 16 '12 at 08:01
  • 2
    To write one
    ... kinda ;) And it's not that I don't want to do it. I thought a good programmer was supposed to 'keep it simple'. And 50 lines of code to get a newline didn't feel like keeping it simple. That's why I wanted to check if there wasn't another way.
    – sander Oct 16 '12 at 08:02
  • If you feel that this is something that you need to use in multiple projects it's pretty trivial to externalize this custom helper into a separate assembly or even a custom NuGet package so that you don't need to repeat it. This way you will keep it simple. All you would have to do is type the following command in your NuGet Console: `Install-Package MySuperNugetPackage`. – Darin Dimitrov Oct 16 '12 at 08:05
  • This will probably be a 1 page thing. Thank you for your solution. I will try it now. – sander Oct 16 '12 at 08:10
  • A Helper that does .Replace("<br/>","
    ") also did the trick.
    – sander Oct 16 '12 at 08:19
  • Yeah, many things could do the trick. I've posted one that I would use. – Darin Dimitrov Oct 16 '12 at 08:20
  • Darin is right. Listen to him :). His code is what I suggested you write - but he has kindly provided the code. His MVC3 stuff is always gold. – GraemeMiller Oct 16 '12 at 08:26
  • I know him and his reputation (he has helped me a lot by answering other peoples questions too) so I have no doubt that this is the best way to fix this issue and I appreciate the effort, Darin. But I think that the real problem is that Html.ValidationMessage doesn't accept HTML-tags. I wonder why that is? Because they are forcing us to write extensions (or less flexible helpers) just to get something as trivial as a break. – sander Oct 16 '12 at 09:13
  • 1
    @S4NDERR, wonder no more - there are no Gods working at Microsoft. They cannot implement every single feature that might come to our minds. In order to implement a feature, specifications need to be written for this feature, it needs to be implemented, tested, documented, integrated into the existing framework, regression tests need to be done, etc... Do you even realize how much does it cost to implement a feature into the .NET framework? If they implemented all features we wanted then we would never see a new version coming out. – Darin Dimitrov Oct 16 '12 at 09:16
  • 1
    I'm not sure about this, but isn't converting tags to string a feature rather then leaving them raw? Let's just let it be, cause I'm feeling a lot of hostility. – sander Oct 16 '12 at 09:33
1

try this one

append
tag after each error message and use Html.Raw() method to display your content Html.Raw will decode HtmlContent.

you message like 
 Field 1 is required <br/>Field 4 is required<br/> 

In View

Html.Raw("Yore Error Message")
Shivkumar
  • 1,903
  • 5
  • 21
  • 32
  • It didn't work for me. I should mention that I am constructing the message in a custom exception. I will update my post. – sander Oct 16 '12 at 07:42
1

In case anyone is looking for it, here is how to do this for a validation summary:

@Html.Raw(HttpUtility.HtmlDecode(Html.ValidationSummary(true).ToHtmlString()))
camainc
  • 3,750
  • 7
  • 35
  • 46
1

Appreciated I am a bit late to this party, but just had this issue and using plain old css also works well:

<style>
    .field-validation-error::after {
        content: "\a";
        white-space: pre;
    }
</style>
s1cart3r
  • 334
  • 1
  • 4
  • 9
0

Are you displaying them in a validation summary? I don’t think it supports html for line breaks etc. I'd create a custom html helper based on validation summary that displays html.

The same applies to validationmessage so probably need to make a custom helper for that

GraemeMiller
  • 11,973
  • 8
  • 57
  • 111
0

what I do is bunch them in a div

       <div class="Errors">

        @Html.ValidationMessageFor(m => m.Name)<br/>
        @Html.ValidationMessageFor(m => m.LName)<br />
      </div>

then create a class

     .Errors {
          color: red;
          font-size: 10px;
          font-weight: bold;
          }

but if you wanna do a multiline error then what Leinel mentioned is the best way.the reason I bunch them is some users will not see the error with long forms and they'll just start calling us.. ^^,

CyberNinja
  • 872
  • 9
  • 25