Razor View Engine: Complex looping and HTML

2020-02-20 07:41发布

问题:

I have lots of complex HTML reports in my current project where there we perform lots of conditional rendering of TRs and TDs with rowspans and colspans.

It could sometimes look like this (this is extremely simplified):

<tr>
@foreach (var ourItem in ourList) {
   if (ourItem != ourList.First()) {
      <tr>                
   }
   <td></td>
   </tr>
}

However, Razor claims: "The foreach loop is missing a closing "}" character". (within Visual Studio)

I've tried to wrap the <tr> in <text></text> which makes the closing } problem go away only to find this when run: "Encountered end tag "tr" with no matching start tag. Are your start/end tags properly balanced".

How would I do this kind of conditional rendering while convincing Razor not to bother about the HTML at all, cause the HTML is balanced when all the looping is done. Or at least that was the case when the ASP.NET View Engine was used.

回答1:

Visual Studio Intellisense and syntax highlighting is not one of the best but in this case it warns you that if the condition is not satisfied, you might get invalid markup and you shouldn't blame it for this.

The important thing is that your project runs fine but you might consider externalizing this logic into HTML helpers because if what you are saying is true that this is a simplified version of what you have in the views I don't even want to imagine how your actual code looks.

IMHO having so much conditional logic in a view is an abuse. You definitely should consider using HTML helpers or controls such as MVCContrib Grid.


UPDATE:

You may try the following hack:

<tr>
@foreach (var ourItem in ourList) {
   if (ourItem != ourList.First()) {
      @:<tr>                
   }
   @:<td></td>
   @:</tr>
}


回答2:

Razor depends on matching tags to determine the automatic transitions between code and markup. You cannot "disable" this feature of Razor (at least not without rewriting large parts of the Razor parser).

You can work around it by using Darin's suggestion, though I don't understand (at least not from your simplified example) why your view needs to be so convoluted. Why not write the following code instead:

@foreach (var ourItem in ourList) {
   <tr>
   <td>...</td>
   </tr>
}

While tags might balance out in the generated markup, the source that you provided makes it very difficult to reason about its correctness.



回答3:

When trying to use rowspan and trying to get a structure like

<table>
   <tr>
       <td rowspan=2>1:st col</td>
       <td>2:nd col</td>
   </tr>
   <tr>
       <td>2:nd col</td>
   </tr>
</table>

You could try:

@{ 
    var ourList = new List<string> { "1", "2", "3" };
}

<table border=1>
@foreach(var ourItem in ourList){
    <tr>
    @if (ourItem == ourList.First())
    {
        <td rowspan="@ourList.Count()">@ourItem</td>
    }
    <td>@ourItem</td>
    </tr>
}
</table>


回答4:

I had a similar problem - my solution Html.Raw("");

    if (isTrue)
    {
        <text><div></text> }
   ...

    if(isTrue) {
        @Html.Raw("</div>"); // <-- closing tag!
        }