tags:

views:

2914

answers:

15

Here's a PHP example of mine. Can anyone find a shorter/easier way to do this?

<? foreach($posts as $post){?>
    <div class="<?=($c++%2==1)?‘odd’:NULL?>">
     <?=$post?>
    </div>
<? }?>

<style>
    .odd{background-color:red;}
</style>

Examples in other languages would be fun to see as well.

+10  A: 

Fundamentally - no. That's about as easy as it gets. You might rewrite it a bit shorter/cleaner, but the idea will be the same. This is how I would write it:

$c = true; // Let's not forget to initialize our variables, shall we?
foreach($posts as $post)
    echo '<div'.(($c = !$c)?' class="odd"':'').">$post</div>";
Vilx-
Thanks for that, works perfectly. Here's what I changed it to to alternate between two TR classes (odd and even)<?php echo '<tr'.(($c = !$c)?' class="odd"':' class="even"').">"; ?>
Coffee Cup
+3  A: 

Maybe a function with a static variable?

<?php

function alternate_row_color($css_class) {
    static $show = true;

    $show = !$show;

    if ($show) {
        return $css_class;
    } else {
        return NULL;
    }
}

?>

Then to use it (using your example):

<?php foreach($posts as $post) { ?>
    <div class="<?=alternate_row_color('odd')?>">
        <?=$post?>
    </div>
<?php } ?>
yjerem
And that's shorter? O_o
Vilx-
You only define the function once, then have a nice short and very readable call to the function everywhere you want to use it.
yjerem
That seems like a pretty good example but it seems like for these basics it's nice to have a snippet that you can just throw in whenever it pops up.
thrashr888
statics may be difficult to read/understand at first glance. The idiom in the OP is better understood. Also, this doesn't work if you have more than one thing alternating at once (rows then columns, for example, would break with an odd number of columns).
strager
A: 

It's short enough as it is, but I would probably wrap it into some helper function with a clear name. That way it's more obvious what's going on and you won't have to repeat that logic in all templates where you need it.

PEZ
+1  A: 
<?php $alt = true; foreach ($posts as $post): $alt = !$alt; ?>
<div<?php echo $alt ? ' class="odd"' : ''; ?>>
    <!-- Content --> 
</div>  
<?php endforeach ?>

Would be the simplest and clearest way to do it.

navitronic
pretty much the same as @Vilx- (who posted earlier) but a good one nonetheless.
thrashr888
+5  A: 

Smarty has it inbuilt:

{section name=rows loop=$data}
<tr class="{cycle values="odd,even"}">
   <td>{$data[rows]}</td>
</tr>
{/section}

So does Django:

{% for o in some_list %}
    <tr class="{% cycle 'row1' 'row2' %}">
        ...
    </tr>
{% endfor %}
Gerald Kaszuba
+6  A: 

Using CSS3 you can do something like this:

div:nth-child(odd)
{
  background-color: red
}

But better not use that for a few years if you actually want your users to see the color...

Ole J. Helgesen
+1  A: 

If you want to do it on the display end and are comfortable with or otherwise already using javascript, libraries like jQuery will often have :odd and :even selectors, which you can then hook up to adding specific style properties or hooking into CSS more generally by adding classes.

Glazius
+12  A: 

If you'd like to have less in-line PHP, a great way of doing it is via JavaScript.

In jQuery, it's simply:

<script type="text/javascript">
  $('div:odd').css('background-color', 'red');
</script>

Max
I don't use jQuery but that looks like a nice, clean bit of code to use.
thrashr888
I second this as well. Making odd-numbered cells a different color is a design concern, so it would be best to deal with in in JS or CSS rather than the business logic (PHP).
Bob Somers
@Bob: The PHP here is printing out HTML, which is part of the presentational logic as it is.
Rob
+2  A: 

Just for fun

Assuming you can use CSS3 selectors you can do something like

<div class="posts">
<? foreach($posts as $post){?>
    <div>
        <?=$post?>
    </div>
<? }?>
</div>

<style>
    div.posts div:odd{background-color:red;}
</style>

Even with CSS2 support and mootools (javascript library) you can substitute the style with this javascript

<script type="text/javascript">
    // obviously this script line should go in a js file in a onload (or onDomReady) function
    $$('div.posts div:odd').setStyle('background-color','red');
</script>

If you don't have anything but php a it you can simplify a bit yous code using an array

<? $isodd=array('','odd');
   $c=0;
   foreach($posts as $post){?>
    <div class="<?=$isodd[$c++%2]?>">
        <?=$post?>
    </div>
<? }?>
Eineki
That will generate a warning on the first iteration since $c is uninitialized, and also you're referencing 'c' when you should be referencing '$c', which will either generate an error or warning, or ineffective behavior. Can't remember which.
Brian Cline
@Brian Cline: thanks for your comment. Edited the post according;
Eineki
+1  A: 

You can encapsulate the logic as follows:

<?php

class ListCycler {
    private $cols, $offs, $len;

    // expects two or more string parameters
    public function __construct() {
        $this->offs = -1;
        $this->len = func_num_args();
        $this->cols = func_get_args();

        foreach($this->cols as &$c)
            $c = trim(strval($c));
    }

    // the object auto-increments every time it is read
    public function __toString() {
        $this->offs = ($this->offs+1) % $this->len;
        return $this->cols[ $this->offs ];
    }
}
?>
<html>
<head>
  <style>
    ul#posts li.odd { background-color:red; }
    ul#posts li.even { background-color:white; }
  </style>
</head>
<body>
  <div>
    <h3>Posts:</h3>
    <ul id="posts"><?php
        $rc = new ListCycler('odd','even');
        foreach($posts as $p)
            echo "<li class='$rc'>$p</li>";
    ?></ul>
  </div>
</body>
</html>
Hugh Bothwell
should __get() not be __toString() ?
Tom Haigh
Why the trim()? That makes the class less usable.
strager
@tomhaigh, Fixed. =]
strager
Wow. You have a very very strange idea of "simpler"
nickf
nickf: (grin) Well, obviously you write the ListCycler class once and store it in your library code. When you *use* it, it is very simple - create a ListCycler object then call it repeatedly, all the logic is hidden.
Hugh Bothwell
+3  A: 

Don't forget! If you use a Javascript solution (jquery, prototype or anything else) you will have a small flick when page loads. In fact, until the page is fully loaded, you won't have the "Zebra" on your rows. For some people this might be a problem.

Ionut Staicu
And, of course, if someone has disabled Javascript, they will never see it.
Graeme Perrow
+1  A: 

On a side noe, to alternate between two values a and b, a nice way of doing it in a loop is this:

x = a;
while ( true ) {
    x = a + b - x;
}

You can also do this without addition and subtraction:

x = a ^ b ^ x;

where ^ is the XOR operation.

If you just want to alternate between 0 and 1, you can do this:

x = 0;
while ( true ) {
    x = !x;
}

You could of course use x as an index of colors, CSS style classes and so on.

csl
A: 

Been using something like this:

<?php
function cycle(&$arr) {
    $arr[] = array_shift($arr);
    return end($arr); 
}

$oddEven = array('odd', 'even');
echo cycle($oddEven)."\n";
echo cycle($oddEven)."\n";
echo cycle($oddEven)."\n";
A: 

i always name my zebra rows "row0" and "row1" - this makes the code a bit simpler.

<?php  // you should always use the full opening tag for compatibility
$i = 0;
foreach ($rows as $row) {
    echo '<tr class="row' . ($i++ % 2) . '">...</tr>';
} 
?>
nickf
Wow! That seems like the shortest one ever!
thrashr888
@thrashr :if you `foreach ($rows as $i => $row)` you can remove the `$i = 0`. But all this depends on getting your rows as an array before you can foreach over them.
Ollie Saunders
A: 
DEFINITIVE ANSWER:

// THE FUNCTION
function row_color($cnt,$even,$odd) { 
echo ($cnt%2) ? "<tr bgcolor=\"$odd\">" : "<tr bgcolor=\"$even\">"; 
} 

// HOW TO USE IT
$cnt=0;
while ($row = mysql_fetch_array ($result)) {
row_color($cnt++,"e0e0e0","FFFFFF");
}
Sam Sun