Snippets

Create an account or login to be able to add, comment and rate snippets.

Navigation

Alphabetical index

Suppose you have a list of items (products, contacts, etc) that you want to look up by name. You want them paginated by letter of the alphabet, not by a certain number of items on each page (the default pagination behavior). You will have a navigator that includes every letter of the alphabet, but only the letters that actually have items will be links. The current letter you are looking at will be highlighted. This is similar to a phone book.

Drawbacks

The drawback to using this method is that the entire contents of the table have to be loaded for each page in order to build the array of first letters for the navigator. Perhaps there would be a way to query the database for just the DISTINCT first letters of the LNAME field, in effect: SELECT DISTINCT substr(lname,1,1) FROM phonebook. If anyone knows how to go about that, please comment.

First, create your action in action.class.php:

public function executeList()
{
  $c = new Criteria();
  $c->addAscendingOrderByColumn(PhoneBook::LNAME);
  $entries = PhoneBook::doSelect($c);
 
  //now we need an array of all the first letters.  
  //At the same time we're looping, we'll put all the 
  //items we need for this page into a separate array
  $pageLetter = strtoupper($this->getRequestParameter('page','A'));
  $arrayOfFirstLetters = array();
  $thisList = array();
  $x=0;$y=0;
  foreach($entries as $entry)
  {
    $firstLetter = strtoupper(substr($entry->getLName(),0,1));
    $arrayOfFirstLetters[$x++]=$firstLetter;
    if($pageLetter==$firstLetter)
    {
      $thisList[$y++] = $entry;
    }
  }
  $arrayOfFirstLetters = array_unique($arrayOfFirstLetters);
  sort($arrayOfFirstLetters);
 
  //make the arrays available to the page template
  $this->page = $pageLetter;
  $this->pageLinks = $arrayOfFirstLetters;
  $this->names = $thisList;
}

And the template, listSuccess.php:

<?php include_partial('alphaPager',array('letters'=>$pageLinks,'thisPage'=>$page)) ?>
<table>
  <?php foreach ($names as $name): ?>
    <tr>
      <td>
        <?php echo link_to($name->getLName().', '.$name->getFName(), 'phonebook/show?id='.$name->getId()) ?>
      </td>
    </tr>
  <?php endforeach; ?>
</table>

And now the partial template, _alphaPager.php:

<div id="alphapager">
<?php
$x='A';
for($y=0;$y++<26;$x++)
{
  if($y>1)
  {
    echo ' | ';
  }
  if($x==$thisPage)
  {
    echo '<font class="alhpaHL">'.$x.'</font>';
  }
  else
  {
    if(array_search($x,$letters))
    {
      echo link_to($x,'phonebook/list?page='.$x);
    }
    else
    {
      echo $x;
    }
  }
}
?>
</div>
by Eric Heimerman on 2006-06-12, tagged alphabetical  pagination 

Comments on this snippet

gravatar icon
#1 Romain Dorgueil on 2006-06-13 at 03:32

maybe try to copy the addSelectColumns of the base class (BaseXxxPeer) to addFirstLetterColumns in the derived class (XxxPeer), and a doSelectFirstLetter:

public static function addFirstLetterColumns(Criteria $criteria)
{
$criteria->addSelectColumn("substr(".self::LNAME.",1,1)");
}
 
public static function doSelectFirstLetters(Criteria $criteria, $con = null)
{
  if ($con === null) $con = Propel::getConnection(self::DATABASE_NAME);
 
  if (!$criteria->getSelectColumns())
  {
    $criteria = clone $criteria;
  CacheEarningByDayPeer::addFirstLetterColumns($criteria);
  }
 
  // Set the correct dbName
  $criteria->setDbName(self::DATABASE_NAME);
 
  $criteria->setDistinct(true);
  $rs = self::doSelectRS($criteria, $con);
 
  while($rs->next())
  {
    $result[] = $rs->getString(1);
  }
 
  return $result;
}

By the way, it's just an idea i got i have no idea if it works, but it should, propel way :p (i've used about this adding a hydrateSum in the row class to retrieve sums of every float columns in a table and that works nice... well just take 3 hours more to code than SQL...)

<MESSAGE SUBLIMINAL>Elargissez la fenetre de commentaires!!!</MESSAGE>

gravatar icon
#2 Feijão Costa on 2008-10-02 at 04:58

If dont show the First Letter ('A') in your list, try use "===" on "array_search", like this:

<div id="alphapager"> <?php $x='A'; for($y=0;$y++<26;$x++) { if($y>1) { echo ' | '; } if($x==$thisPage) { echo '<font class="alhpaHL">'.$x.'</font>'; } else { if(array_search($x,$letters)) { echo link_to($x,'phonebook/list?page='.$x); } else { echo $x; } } } ?> </div>

You need to create an account or log in to post a comment or rate this snippet.