Search code examples
jstl

Limit c:forEach to a maximum when using an c:if condition in its body


I've got a problem with if condition. I'm getting data from DB and everything is viewed on 2 website tables. Tables on website should be limited to 3 rows only. In DB there is a column named 'screen'. 'screen' can be 'first', 'second' or 'both'. 'first' is a first table, 'second' is a second table, 'both' means both tables. For example if I add data as 'first' screen it should be viewed in first table, if I add data as 'both' it should be viewed in both tables etc. I limited it to 3 rows so the problem is if I add 3 'first' screens and 1 'both' screen I see 3 rows on first table but there isn't any row at second screen. That code is for first table:

<c:forEach items="${foo}" var="c" varStatus="status">
      <c:if test="${status.count <= 3 && c.screen.equals('both') || status.count <= 3 && c.screen.equals('first')}">

            <tr><td>something_bla_bla</td></tr>

      </c:if>
 </c:forEach>

Code for second table is almost same - diffrence is only c.screen.equals('second') Adding 3 'first' shows 3 rows - that's OK, Adding 3 'both' shows 3 rows - that's OK, But if I add 3 'first' and 1 'both' that 'both' record should be viewed in second table and it isn't because of that 3 limit.


Solution

  • It's just a matter of counting how many rows you have outputted. For example:

    <c:set var="count" value="0"/>
    <c:forTokens items="first,second,second,both,first,both,second"
                 delims=","
                 var="item">
      <c:if test="${count lt 3 and 'both,first'.contains(item)}">
        <c:out value="${item}"/>
        <c:set var="count" value="${count + 1}"/>
      </c:if>
    </c:forTokens>
    
    <br/>
    
    <c:set var="count" value="0"/>
    <c:forTokens items="first,second,second,both,first,both,second"
                 delims=","
                 var="item">
      <c:if test="${count lt 3 and 'both,second'.contains(item)}">
        <c:out value="${item}"/>
        <c:set var="count" value="${count + 1}"/>
      </c:if>
    </c:forTokens>
    

    This will output (ignoring whitespace):

    first both first<br/>
    second second both
    

    Please note that I'm using 'both,first'.contains(item) which has the same effect as (item eq 'both' or item eq 'first'), but is shorter (especially if you would have move strings to check).