6

I'm building a grid with Twitter Bootstrap. How do I add the closing row </div> tags after every 2 entries?

I need the HTML to look like this:

<div class="row">
  <div class="span6">...</div>
  <div class="span6">...</div>
</div> 
<div class="row">
  <div class="span6">...</div>
</div>

I think I need something like this:

<div class="row">
  {exp:channel:entries channel="channel_name" dynamic="no"}
  <div class="span4">
    ...
  </div>
  <!-- conditional here to close /.row -->
  {/exp:channel:entries}

I think I could use {switch} tag to accomplish this, but I also need a way to close the row if there are an odd number of entries as well. Is there an easy way to do this without using PHP and modulus somehow?

  • Alex, was there a correct answer to this question posted? – Anna_MediaGirl Dec 12 '12 at 5:14
10

You should put the closing </row> outside your channel entries tag, to be consistent, and use a switch statement to add the middle rows every third entry:

<div class="row">
    {exp:channel:entries channel="channel_name" dynamic="no"}
        <div class="span4">
            ...
        </div>
        {switch='||</div><div class="row">'}
    {/exp:channel:entries}
</div><!-- /row -->

Note that we are using {switch='||</div><div class="row">'} here to show a row every third entry. By placing two pipes (|) at the start of the switch statement, you are essentially switching between:

  • Nothing
  • Nothing
  • </div><div class="row">

This is the easiest way to insert html every nth element - simply by adding extra pipes to your switch statement.

  • 1
    Just to clarify, the switch statement will alternate between as many piped sections as you ad. There is no setting to tell it how frequently to alternate, that is just done by adding more or less pipes. In Adrian's example, the first two times the switch statement runs, it returns a blank value. It's an obvious point, but thought I'd mention it because I found it a bit counterintuitive at first to be passing blank values. – Ben Parizek Nov 16 '12 at 1:03
  • Good point, I'll clarify that in the answer – Adrian Macneil Nov 16 '12 at 1:24
  • This does work, except it creates an empty row every third entry. Like this: jsfiddle.net/alexroper/H9hbx. Your solution uses less template logic, but I like my solution better because it keeps the HTML cleaner :) – Alex Roper Nov 16 '12 at 2:31
  • You sure you copied it exactly? There is no way it should be generating empty rows. – Adrian Macneil Nov 16 '12 at 2:36
  • Yes, every third entry will add a new row. For example if there are only 3 rows, it creates a new row and immediately closes the </div>. Wrapping the {switch} tag with {if count != total_results} fixes this problem tho. But you made me realise I didn't need a second conditional to test for the last row ({if count == total_results}). I could just add the closing </div> outside the channel entries tag. Thanks! – Alex Roper Nov 16 '12 at 2:47
4

It's a common task to want r rows of x items, and I've sometimes got myself tangled with switch and conditionals etc still finding I end up with empty or unclosed tags. I find the EEGrouper add-on http://devot-ee.com/add-ons/eegrouper is a quick and easy way to handle all cases.

  • Ah ha! I knew someone had written a plugin for this. This solution is easier to think about and definitely more powerful, but it adds a lot more code than my solution. I have definitely wished {switch} could be used as a tag pair before. It look like EEGrouper would do the trick. – Alex Roper Nov 16 '12 at 21:38
  • I was going to suggest the exact same thing. EEGrouper really came in handy for me on a recent project. – Stuart McCoy Nov 19 '12 at 3:25
4

I too might go for the {switch} method. But I would also question if using Bootstrap's CSS classes are the best way to mark up your page.

Have you considered using their LESS classes? You could then possibly keep your EE and HTML as separated from the design as this...

<section id="section-name">
    {exp:channel:entries channel="channel_name" dynamic="no"}
        <article>
            Your stuff goes here
        </article>
    {/exp:channel:entries}
</section>

Then within your stylesheet perhaps something like this...

#section-name {
    article {
        .span(2); // load GS - never used Bootstrap so may be incorrect syntax

        &:nth-child(even):after {
            .clearRow(); // call our clearRow mixin after every 2nd article which emulates ending the row class
        }
    }
}

// Our clear row mixin
.clearRow(){
    content: "";
    display: block;
    clear: left;
}

It may or may not work. But if it does it'd certainly separate your styles from your markup. Something that I dislike about Bootstrap using CSS is it's reliance on obscure classes and unnecessary syntax.

Another small win of this method is that it is marginally less for ExpressionEngine to process and by having the clearRow mixin in LESS you could apply this method on any channel and any template.

Of course it relies on a certain level of browser compliance, which is the trade-off.

  • In my particular case, I'm building a quick prototype with Bootstrap so I'm trying to use all out-of-the-box styles. – Alex Roper Nov 19 '12 at 21:47
4

I managed to find a simple solution as I wrote the question. This just uses a combination of {switch} and a {if count != total_results} conditional:

<div class="row">
  {exp:channel:entries channel="channel_name" dynamic="no"}
  <div class="span4">
    ...
  </div>
  {if count != total_results}
    {switch='|</div><!-- /row --> <div class="row">'}
  {/if}           
  {/exp:channel:entries}
</div><!-- /row -->

There are many other great add-ons that solve this problem in the answers below. But for me, this out-of-the-box solution is the simplest.

  • this solution works! Very clean and simple. – Tad Ward Feb 7 '13 at 5:55
3

My approach to handling this issue is to use the SurgerEE addon which provides (among many other useful things) modulo operator support via a plugin call, so you can then do something like this:

<div class="row">
{exp:channel:entries channel="channel_name" dynamic="no"}
  <div class="span4">
    ...
  </div>
{if '{exp:surgeree:modulo numerator="{count}" denominator="2"}' == 0 && count == total_results}
  </div><!-- /row -->
  <div class="row">
{/if}           
{/exp:channel:entries}
</div><!--//.row-->

While in general I'd always tend to prefer solutions that don't require third party code, here I think there's a real benefit in the increased readability of your code (both for others and for yourself at a later date). {switch='||</div><div class="row">'} works and is native functionality, but is not hugely intuitive and hard to scan, whereas {exp:surgeree:modulo} is very explicit, and makes it super clear what this code is doing.

3

I'd like to add that with the Modulus Operator added to EE in 2.7.1 that this can be easily achived now with the following code, based on Bootstrap 3 (example using a Grid fieldtype for the output):

<div class="container">
    <div class="row">
    {gallery}

        {if gallery:index % 3 == 0 OR gallery:index != 0} 
            </div>
            <div class="row">
        {/if}

        <div class="col-sm-4">
            <p>{gallery:title}</p>
        </div>

    {/gallery}
    </div>

This will close the row and make a new one after every 3rd element.

0

You can do this using Will Hunting and it's mod() function. This will ensure that no blank row is included at the end of the output by checking if the $count variable is equal to total_results, and avoids outputting a blank row div if there are no results.

{exp:will_hunting:solve_pair}
    {$count=0}
    <div class="row">
        {exp:channel:entries channel="channel_name" dynamic="no"}
            {$count=$count+1}
            {!-- we're on the first item, so output our starting row div --}
            {if {$count} == 1}
                <div class="row">
            {/if}
            <div class="span4">
                content
            </div>

            {!-- close the previously open row div if this is a multiple
                 of 3, or if it is the last result --}
            {if mod({$count}, 3) == 0 || {$count} == {total_results} }
                </div>

                {!-- if there are more records left, create a new row div --}
                {if {$count} != {total_results}}
                    <div class="row">
                {/if}
            {/if}
        {/exp:channel:entries}
    </div><!-- /row -->
{/exp:will_hunting:solve_pair}
  • Does Will Hunting need a {$count} variable set or can it just use {count}? Or does this not work because of a parse order problem? – Alex Roper Nov 19 '12 at 21:50

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.