Magento – How to program yes/no/any in grid with serializer (within edit form)

filtergridgrid-serlizationtabs

I have edit page of some entity with tab with grid and serializer.
So, above checkboxes we can see the dropdown which is responsible of list of chosen elements or non-chosen element or show all of ones.
It doesn't work from me. When I press Yes/No and Search it doesn't affect getting items on ajax request.

Add column:

$this->addColumn(
    'selected_countries',
    array(
        'type'       => 'checkbox',
        'index'      => 'country_id',
        'align'      => 'center',
        'name'       => 'selected_countries',
        'field_name' => 'selected_countries',
        'values'     => $this->getSelectedItems(),
    )
);

layout update:

<reference name="left">
    <block type="restrictshipping/adminhtml_rule_edit_tabs"
           name="restrict_shipping_rule_edit_tabs"
           as="rule.edit.tabs">
        <block type="restrictshipping/adminhtml_rule_edit_tab_countriesList"
               name="restrict_shipping_rule_edit_countries_list"
               as="rule.edit.tab.countries.list">
        </block>
        <action method="addTab" >
            <name>rule_edit_tab_countries_list</name>
            <block>rule.edit.tab.countries.list</block>
        </action>
    </block>

            <block type="adminhtml/widget_grid_serializer" name="related_grid_serializer">
                <action method="initSerializerBlock">
                    <grid_block_name>restrict_shipping_rule_edit_countries_list</grid_block_name>
                    <data_callback>getSelectedItems</data_callback>
                    <hidden_input_name>selected_countries_ids</hidden_input_name>
                    <reload_param_name>country_id_reload</reload_param_name>
                </action>
                <action method="setFormId">
                    <id>edit_form</id>
                </action>
            </block>
</reference>

Also it doesn't send selected items IDs.

And there is a strange behavior:

public function getCondition()
{
    if ($this->getValue()) {
        return $this->getColumn()->getValue();
    }
    else {
        return array(
            array('neq'=>$this->getColumn()->getValue()),
            array('is'=>new Zend_Db_Expr('NULL'))
        );
    }
    //return array('like'=>'%'.$this->getValue().'%');
}

because Mage/Adminhtml/Block/Widget/Grid.php:470

I believe it must use in if value === 1 and nin if value === 0 and not use any filter when value === ''. I don't understand how it can work…

Best Answer

Seem, I found an answer, but it doesn't show that Magento works from the box with it... (in the example "regions" entities not countries as in answer)

Add checkbox column:

/**
 * Add columns to grid
 *
 * @return $this
 * @throws Exception
 */
protected function _prepareColumns()
{
    $this->addColumn(
        'selected_filter',
        array(
            'type'       => 'checkbox',
            'align'      => 'center',
            'index'      => 'region_id',
            'field_name' => 'selected_regions',
            'values'     => $this->getSelectedItems(),
        )
    );
    //other your code...
}

Catching selected rows (in grid tab class):

/**
 * Set selected items to collection
 *
 * This method needed to make proper working checkbox filtering
 * 'cause it does not work from the box.
 *
 * @param array $data
 * @return $this
 */
protected function _setFilterValues($data)
{
    if (isset($data['selected_filter'])) {
        $condition = null;
        if (1 === (int)$data['selected_filter']) {
            $condition = 'in';
        } elseif (0 === (int)$data['selected_filter']) {
            $condition = 'nin';
        }
        if ($condition) {
            /** @var $column Mage_Adminhtml_Block_Widget_Grid_Column_Filter_Checkbox */
            $column = $this->getColumn('selected_filter');
            $column->getFilter()->setValue($data['selected_filter']);
            $this->getCollection()->addFieldToFilter(
                'main_table.region_id',
                array(
                    $condition => $column->getValues()
                )
            );
        }
        unset($data['selected_filter']);
    }
    if ($data) {
        parent::_setFilterValues($data);
    }
    return $this;
}

Get selected items implementation (in grid tab class):

/**
 * Get selected regions IDs
 *
 * @return array
 */
public function getSelectedItems()
{
    if ($this->getRequest()->isPost()) {
        //get from request on ajax update
        return (array)$this->getRequest()->getParam('selected_regions');
    }

    //here your logic to get IDs from database
    return array(1, 2, 3, 4); //example data
}

Adding serializer into a layout update file (added to "left" block):

<!--Serializer for the regions grid-->
<block type="adminhtml/widget_grid_serializer" name="related_grid_serializer">
    <action method="initSerializerBlock">
        <!--Grid block name in layout-->
        <grid_block_name>your_grid_block_name</grid_block_name>
        <!--Callback of grid block-->
        <data_callback>getSelectedItems</data_callback>
        <!--Param name to send to save, 
            you will get it from $_POST['countries']['regions']
            (it means from request object by the same path)-->
        <hidden_input_name>countries[regions]</hidden_input_name>
        <!--Param name of checkboxes, 
            it's needed to for ajax requests 
            and proper work of yes/no/any dropdown-->
        <reload_param_name>selected_regions</reload_param_name>
    </action>

    <!--Add serializer setting form ID if it wasn't rendered within the form-->
    <action method="setFormId">
        <id>edit_form</id>
    </action>
</block>

So, we need to add a bit self code... Please notify me if there is a native approach exists.