i_ll_be_back
i_ll_be_back

Reputation: 317

Error in MVC View at Razor syntax

I have a sidebar item which contains a list of comments. I want this item to show only if there are any available comment in the beginning and in order for my template to work I have to put a different style to the first comment than the rest. All the comments are being passed on my Model.

Here is my approach:

@if(Model.Comments?.Count > 0) {
<div class="sidebar_item">
    <div class="item_inner slider">
        <h4>See what students say:</h4>
        <div id="single_banner">
            <ul class="slides">
            @for (int i = 0; i < Model.Comments.Count; i++)
            {
                if (i > 0){ 
                    <li style="display:none;">
                }
                @if( i == 0)
                {
                    <li>
                }
                @Model.Comments[i].Comment
                    <div class="carousal_bottom">
                        <div class="thumb">
                            <img src="img/courses/testi_thumb.png" draggable="false" alt="" />
                        </div>
                        <div class="thumb_title">
                            <span class="author_name">@Model.Comments[i].Student</span>
                        </div>
                    </div>
                </li>
            }
            </ul>
        </div><!--end banner-->
    </div><!--slider-->
</div><!--end sidebar item-->
}

The problem is that this doesn't work and I get errors that some curly brackets are missing or that some elements haven't closed properly. Any help appreciated.

Upvotes: 0

Views: 990

Answers (1)

Erik Philips
Erik Philips

Reputation: 54618

I get errors that [...] some elements haven't closed properly.

The following code isn't recommended because the engine isn't smart enough to determine start/ends for html elements in c# code:

if (i > 0){ 
  <li style="display:none;">
}
@if( i == 0)
{
  <li>
}

So I generally put the logic directly in the tag:

<li style="@(i > 0 ? "display:none;" : string.Empty)">

However I'm not really a fan of logic in my view. Additionally to make things easier IMHO, I would have a comment display template. And I personally think there is no good reason to not use classes. Eventually my code would look like:

controller:

foreach(var comment in Model.Comments)
{
   comment.IsVisible = comment == Model.Comments.First();
}

view:

// Update Model with Property
// bool HasComments { get { return Comments.Any(); } }
// Then the code actually reads/documents itself

@if(Model.HasComments) {
<div class="sidebar_item">
    <div class="item_inner slider">
        <h4>See what students say:</h4>
        <div id="single_banner">
            <ul class="slides">
            @Html.DisplayFor(m => m.Comments);
            </ul>
        </div><!--end banner-->
    </div><!--slider-->
</div><!--end sidebar item-->
}

displaytemplates/comments.cshtml

@{ 
  // View logic, it only deals with html/css/javascript
  var liClass = model.IsVisible ? string.Empty : "is-not-visible"; 
}
<li class="@liClass">
  @Model.Comments[i].Comment
  <div class="carousal_bottom">
    <div class="thumb">
      <img src="img/courses/testi_thumb.png" draggable="false" alt="" />
    </div>
    <div class="thumb_title">
      <span class="author_name">@Model.Student</span>
    </div>
  </div>
</li>

Less code and more encapsulated.

I'd also recommend reading Philip Walton - Decoupling Your HTML, CSS, and JavaScript

Upvotes: 4

Related Questions