20
\$\begingroup\$

Suppose the following model:

public class ViewBookModel
{
    public string Title { get; set; }
    public string Subtitle { get; set; }
}

I'm currently rendering it like this in my Razor view:

<h1>@Model.Title</h1>
@if (Model.Subtitle != null)
{ 
    <h2>@Model.Subtitle</h2>
}

My question is about the Subtitle bit. The above approach feels a little clunky, and can get repetitive (which is probably a bad sign) at times.

Are there any better, less verbose, more elegant ways to handle this situation?


I had considered (a) the option now mentioned in Mat's Mug's answer, as well as (b) moving the condition to the model:

public class ViewBookModel 
{
    // ...
    public string ShowSubtitle { 
        get { return string.IsNullOrEmpty(Subtitle); } 
    }
}

With this change to the view:

@if (Model.ShowSubtitle)

However, that doesn't address my main issue: the verbosity (i.e. 4 lines of view code just to display Subtitle).

\$\endgroup\$
22
\$\begingroup\$

If you find a pattern getting too repetitive, you can use @helper instead:

@helper ShowIfNotNull(string header) {
    @if (!string.IsNullOrEmpty(header))
        @:<h2>header</h2>
    }
}

<h1>@Model.Title</h1>
@ShowIfNotNull(Model.Subtitle)
\$\endgroup\$
  • 3
    \$\begingroup\$ Hadn't heard of @helper before, that's pretty useful. \$\endgroup\$ – Jeroen Vannevel May 29 '14 at 17:00
  • \$\begingroup\$ Welcome to Code Review! Nice first post, I hope you keep reviewing! Feel free to meet the regulars in Code Review Chat :) \$\endgroup\$ – Mathieu Guindon May 29 '14 at 17:02
  • \$\begingroup\$ Thanks again. After some tweaks for syntax (I've suggested it as an edit) this worked for me. I've also added a version that is exposed as an HtmlHelper extension, that allows you to choose the wrapper tag. \$\endgroup\$ – Jeroen Jul 6 '14 at 9:40
  • \$\begingroup\$ @EricB: Alas, my edit was rejected as "too radical". A fair point I guess, though if you agree with my suggestions feel free to merge it into yours and I'll happily change my "Accept" mark to your answer again and delete my own. \$\endgroup\$ – Jeroen Jul 6 '14 at 15:15
  • \$\begingroup\$ If you're going to use this helper method, at least name it ShowIfNotNullOrEmpty so it does exactly what it says... I would not recommend using this however: it's more code and moves markup out of context (you would have to switch back and forth to have an idea of the rendered markup). \$\endgroup\$ – Ronald Mar 13 '18 at 8:25
5
\$\begingroup\$

To give an alternate solution: you can do this with pure CSS3 using the :empty selector.

h2:empty {
  display: none
}

The :empty selector will match on all empty tags. 'Empty' can include HTML-comments, but not whitespace.

Here's a more detailed explanation.

\$\endgroup\$
  • \$\begingroup\$ Outtathebox, +1! With the appropriate selector this may just work, and it's semantically quite "correct" for several of my cases. \$\endgroup\$ – Jeroen May 30 '14 at 16:25
  • \$\begingroup\$ could you add more explanation from the outside link into your answer, that way if the link dies the information is still here on the Answer \$\endgroup\$ – Malachi May 30 '14 at 16:41
4
\$\begingroup\$

Subtitle being a string, a more elegant way of testing whether it's null would be to use string.IsNullOrEmpty(Model.Subtitle), like this:

<h1>@Model.Title</h1>
@if (!string.IsNullOrEmpty(Model.Subtitle))
{ 
    <h2>@Model.Subtitle</h2>
}
\$\endgroup\$
  • \$\begingroup\$ Thanks for your review! I had considered this (should've had a "What I've tried" section in my question, I guess; but as an answer it may help future visitors here equally well). My main concern however was with the verbosity, as addressed by Eric B's answer. \$\endgroup\$ – Jeroen May 29 '14 at 18:07
  • \$\begingroup\$ Great! Feel free to give @EricB a well-earned checkmark :) \$\endgroup\$ – Mathieu Guindon May 29 '14 at 18:24
2
\$\begingroup\$

My answer was originally an edit to @EricB's post, but that edit got rejected by a mod, suggesting it was better suited as a competing answer. If this answer helps you, please consider responding to (upvoting ;)) his answer.


If you find a pattern getting too repetitive, you can use @helper instead:

@helper ShowIfNotNull(string header) {
    if (!string.IsNullOrEmpty(header)) {
        <h2>@header</h2>
    }
}

And use it like this:

<h1>@Model.Title</h1>
@ShowIfNotNull(Model.Subtitle)

Alternatively, you can create an HtmlHelper extension that does the same thing:

public static class StringExtensions
{
    public static IHtmlString ShowIfNotNull(this HtmlHelper htmlHelper, string text, string tagName)
    {
        var builder = new TagBuilder(tagName);
        builder.SetInnerText(text);
        return new HtmlString(builder.ToString());
    }
}

Which can be called like this:

@Html.ShowIfNotNull(Model.Subtitle, "h2")
\$\endgroup\$

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service, privacy policy and cookie policy

Not the answer you're looking for? Browse other questions tagged or ask your own question.