Magento Grid Filtering – Exclude Certain Field Values by Default

admincollection-filteringgrid

I have a custom admin grid that shows grid data from a custom table. One of the fields in this custom table is "status" which is added to the grid with the following values and function.

$this->addColumn('status', array(
  'header'    => Mage::helper('ifactory_schoollist')->__('Status'),
  'align'     =>'left',
  'index'     => 'status',
  'type'      => 'options',
  'options'   => array('1' => 'Draft', '2' => 'Awaiting Approval', '3' => 'Live', '4' => 'Archived'),
  'filter_condition_callback' => array($this, '_filterStatusCondition')
));

If the row is set to "Draft", "Awaiting Approval" or "Live" it should show and be filterable/searchable as normal. However if the row is set to "Archived" I do not want it to show up unless the user has explicity filtered for "Archived" rows.

My first attempt at this was to filter the collection in the _prepareCollection function like this.

$collection->addFieldToFilter("status", array("neq" => '4'));

This hides it correctly but does not let the user see them if they search for archived rows.

I then tried adding a default filter in _prepareCollection

$this->setDefaultFilter(array('status' => array("1","2","3")));

Along with a custom filter_condition_callback for the column

protected function _filterStatusCondition($collection, $column)
{
  $value = $column->getFilter()->getValue();
  if(!$value) {
    return;
  }

  if(is_array($value)){
    $this->getCollection()->addFieldToFilter('status', array('in' => $value));
  } else {
    $this->getCollection()->addFieldToFilter('status', $value);
  }
}

This worked initially only showing the non-archived columns but letting you filter to show any specific status. However whenever you search by another field or reset filters you lose the default filter arrow and archived results show up again.

I tried adjusting the filter_condition_callback function to counter this but it doesn't seem to be being called when you reset filters or leave the status blank.

protected function _filterStatusCondition($collection, $column)
{
  echo "test a";
  $value = $column->getFilter()->getValue();
  if(!$value) {
    // return;
    $value = array("1","2","3"); // if no value given filter default values
  }

  if(is_array($value)){
    $this->getCollection()->addFieldToFilter('status', array('in' => $value));
  } else {
    $this->getCollection()->addFieldToFilter('status', $value);
  }
}

Best Answer

Try this.
Lose the filter_condition_callback on the column. You need to focus on the _prepareCollection method.

protected function _prepareCollection() {
    $collection = ....;
    ....
    $canShowArchive = false;
    //check if there is a filter.
    $filter = $this->getParam($this->getVarNameFilter(), null);
    //if there is a filter, check if the filter contains the status
    if (!is_null($filter))  {
         //decode the filter
         $filter = $this->helper('adminhtml')->prepareFilterString($filter);
         if (isset($filter['status'])) {
              //if there is a filter by status you may need to show the archive items 
              $canShowArchive = true;
         }
    }
    //if $canShowArchive is false, just filter the collection by status not equal to 'archive'
    if (!$canShowArchive) {
        $collection->addFieldToFilter('status', array('neq'=>4));
    }
    $this->setCollection($collection);
    return parent::_prepareCollection();
}

The code above is not tested but it seams like the way to go.