QCubed - A PHP5 rapid development MVC framework.
Home  |  Updates

qdatagrid qpanel nested

QDataGrid on Nested QPanels

I've searched through the forums and this question has been asked before, but I'm having slightly different issues and haven't been able to find a fix yet so I'm hoping someone might be able to shed some light on the subject. A small diagram might be in order:

QDataGrid <- QPanel (FileListPanel) <- QPanel (BoxPanel) <- QForm

Perhaps there is a better method of doing this, so I'm open to suggestions, but here is the scenario. I'm rendering the FileListPanel through the BoxPanel on a QForm. The reason for doing this is the BoxPanel adds necessary HTML tags and css to render elements on my web page, plus it provides a centralized place to edit these elements. The FileListPanel contains the datagrid itself. To start everything is rendering perfectly, the issue appears when trying to use the built in filter or sort functionality of the QDataGrid (I'm using a generated datagrid with metacontrols). Any time you click to sort a column or filter the datagrid it's rendered exactly the same as before (with the default settings). I'm guessing that the call to update the datagrid isn't making it all the way to the datagrid class or the panel that it is on so the view isn't being updated. I'm not quite sure how to figure out if this is actually what is happening, and then how to fix it. Any info to help point me in the right direction or to help assist in validating my theory would be greatly appreciated.

Tutorial - Nested QDataGrid The How To?

Hi everyone, as my first contribution to the community of qcubed I will explain and demonstrate how to create a nested QDatagrid.

With a MAster QDatagrid and through a button, usually a '+'to prove they can expand, appear a Child QDataGrid with other content as you can see in the screen_1.jpg attach.

Some preconceptions to consider first are:

- Master QDataGrid should go on the FORM.
- Child must be in QPanel QDataGrid (I like it better to say that the style created as User Controls. NET)
- We must always know who are the children and parents the QDataGrids.
- HtmlEntities in QdataGrid always 'False'. I Expend two days looking for this error =P.

Let's start ...

First we need to create the Master QDataGrid...

<?php
   
// Load the QCubed Development Framework
   
require ('../../qcubed.inc.php');

       
// Load User Controls -> This is the First Child QDataGrid.
        // It be  explian later, at the moment the only you need to know is
        // it was created like a .NET User Control and extends from a QPanel.
       
require (__APP_CONTROLS__ . '/records.summary.php');

       
        class
DomainList extends QForm {

               
// Datagrid List Control for Domains
               
protected $dtgDomains;

               
// This is for refresh the QDataGrid and make appear the childs
                // Datagrid becaouse i use ajax.
               
protected function Form_PreRender() {
                   
parent::Form_PreRender();

                   
$this->dtgDomains->Refresh();
                }

                protected function
Form_Create() {
                   
parent::Form_Create();

                   
// Create the Master DataGrid
                    // I make derived from another QDataGrid but is just for
                    // apply styles css, nothing important

                   
$this->dtgDomains = new DomainGridControl($this);
                   
$this->dtgDomains->SetDataBinder('dtgDomains_Bind');

                   
// Here we start, create our first control a simple toogle
                    // button
                   
$this->dtgDomains->AddColumn(
                            new
QDataGridColumn('','<?= $_FORM->render_btnToggleRecordsSummary($_ITEM) ?>
','HtmlEntities=false', 'Width=1px'));

                    // And some other data columns...
                    $this->dtgDomains->MetaAddColumn(QQN::Domains()->Zone,'Name=Domain',
                            array('OrderByClause' => QQ::OrderBy(QQN::Domains()->Zone),
                                  'ReverseOrderByClause' => QQ::OrderBy(QQN::Domains()->Zone, false))
                           );

                    // Second... we need to create out Child QDataGrid sp put them
                    // hide in a column.
                    $this->dtgDomains->AddColumn(
                            new QDataGridColumn('','<?= $_FORM->render_ucRecordsSummary($_ITEM) ?>','HtmlEntities=false','Width=1px'));
                }

                public function dtgDomains_Bind() {
                    // Bind... nothing important...
                }

                // Function to render our toggle button column
                // As you can see we pass as a parameter the item binded in the
                // row of QDataGrid
                public function render_btnToggleRecordsSummary(Domains $objDomain) {

                    // Create their unique id...
                    $objControlId = 'btnToggleRecordsSummary' . $objDomain->Id;

                    if (!$objControl = $this->GetControl($objControlId)) {

                        // If not exists create our toggle button who his parent
                        // is our master QDataGrid...
                        $objControl = new QButton($this->dtgDomains, $objControlId);
                        $objControl->Text = '+';
                        $objControl->CssClass = 'inputbutton';

                        // Pass the id of the bounded item just for other process
                        // on click event

                        $objControl->ActionParameter = $objDomain->Id;

                        // Add event on click the toogle button
                        $objControl->AddAction(new QClickEvent(), new QAjaxAction('btnToggleRecordsSummary_Click',$this->dtgDomains->WaitIcon));
                    }

                    // We pass the parameter of "false" to make sure the control doesn't render
                    // itself RIGHT HERE - that it instead returns its string rendering result.
                    return $objControl->Render(false);
                }


                // Clicking the toogle button...
                public function btnToggleRecordsSummary_Click($strFormId, $strControlId, $strParameter) {

                    // First get the button himself for change '+' to '-'
                    $srcControl = $this->GetControl($strControlId);

                    $intDomainId = intval($strParameter);

                    // Look for our child QDatagrid if is render...
                    $objControlId = 'ucRecordsSummary' . $intDomainId;
                    $objControl = $this->GetControl($objControlId);

                    if ($objControl) {
                        // Ask if our Child DataGrid is visible...
                        if ($objControl->Visible) {
                            // Make it desapear ...
                            $objControl->Visible = false;
                            $srcControl->Text = '+';
                        } else {
                            // Or make it appear...
                            $objControl->Visible = true;
                            $srcControl->Text = '-';
                        }

                        // Important! Refresh the parent QDataGrid...
                        $this->dtgDomains->Refresh();
                    }                   
                }

                // Ladys and Gentleman... Our Child QDataGrid... =P
                public function render_ucRecordsSummary(Domains $objDomain) {

                    $objControlId = 'ucRecordsSummary' . $objDomain->Id;

                    if (!$objControl = $this->GetControl($objControlId)) {

                        // Create the User Control Child QDataGrid passing the
                        // parent, in this case Master QDataGrid and the unique id.
                        $objControl = new RecordsSummary($this->dtgDomains, $objDomain, $objControlId);

                        //Put invisible at the begging, the toogle button gona do
                        //the job
                        $objControl->Visible = false;
                    }

                    return $objControl->Render(false);
                }
        }

DomainList::Run('DomainList', __APP_VIEW_ACCOUNT__ . '/domain.list.tpl.php');
?>

Well thats all for the Master QDataGrid, at here everythings looks normal uh?

ok here is the Child QDataGrid...

<?php
       
// Load the QCubed Development Framework
       
require_once('../../qcubed.inc.php');

       
// Load User Controls -> Load Other QDataGrids Child of this one
        // This is not awseome? QdataGrid can do everything!!
       
require (__APP_CONTROLS__ . '/a.records.list.php');
        require (
__APP_CONTROLS__ . '/cname.records.list.php');
        require (
__APP_CONTROLS__ . '/mx.records.list.php');
        require (
__APP_CONTROLS__ . '/srv.records.list.php');
        require (
__APP_CONTROLS__ . '/spf.records.list.php');


       
// As you can see thie QDataGrid extends the QPanel not a QForm
       
class RecordsSummary extends QPanel {

               
// QDatagrid Records Summary
               
public $dtgRecordsSummary;

               
// dtgDomains -> this is our Master QDataGrid
               
protected $objParentObject;

               
// Protected Objects
               
protected $objDomain;
           
               
// in the contructor pass the item bounded too just for other
                // process
               
public function __construct($objParentObject, Domains $objDomain, $strControlId = null) {

                    try {
                       
                       
parent::__construct($objParentObject, $strControlId);
                       
                       
// Watch out for template later gonna talk about it,
                        // need a trick to look good.
                       
$this->Template = __APP_CONTROLS__ . '/records.summary.tpl.php';

                       
// Setting local the MAster QDataGrid to refresh on
                        // Saves on the Child DataGrid..
                       
$this->objParentObject = $objParentObject;
                       
$this->objDomain = $objDomain;
                      
                       
// Create the child DataGrid as a simply...QDataGrid
                        // normal
                       
$this->dtgRecordsSummary = new QDataGrid($this);
                       
                       
// Bind him, the normal...
                       
$this->dtgRecordsSummary->SetDataBinder('dtgRecordsSummary_Bind', $this);

                       
// Need another Child QDataGrid? ok add their toogle
                        // button...
                       
$this->dtgRecordsSummary->AddColumn(
                            new
QDataGridColumn('','<?= $_CONTROL->ParentControl->render_btnToggleRecords($_CONTROL, $_ITEM) ?>
','HtmlEntities=false', 'Width=1px'));

                       // Add some QDataGrid data to show...
                        $this->dtgRecordsSummary->AddColumn(
                            new QDataGridColumn('', '<?= $_ITEM . " Records" ?>'));
                       // Add if you need another column with the other child QDataGrid to show if you need
                        $this->dtgRecordsSummary->AddColumn(
                            new QDataGridColumn('','<?= $_CONTROL->ParentControl->render_ucRecords($_CONTROL, $_ITEM) ?>','HtmlEntities=false','Width=1px'));
                       
                    } catch (QCallerException $objExc) {
                        $objExc->IncrementOffset();
                        throw $objExc;
                    }
                }

                public function dtgRecordsSummary_Bind() {
                   //Bind...
                }

                // Render other toggle...
                public function render_btnToggleRecords($parControl, $strType) {

                    $strControlId = 'btnToggleRecords' . $this->objDomain->Id . $strType;

                    if (!$objControl = $parControl->GetChildControl($strControlId)) {
                        // But in this case the parent control of the button
                        // woluld be this child QDataGrid, dont forget that...
                        $objControl = new QButton($parControl, $strControlId);
                        $objControl->Text = '+';
                        $objControl->CssClass = 'inputbutton';
                        $objControl->ActionParameter = $strType;

                        // Important! for a better coding we want to all
                        // actions referer to the child QdataGris stay
                        // in the child Qdatagrid, so the actions are now
                        // QAjaxControlAction or QServerControlAction, were the
                        // controlId parameter is $this, becaouse in $this class
                        // is defined the event for this button... kind of easy,
                        // and clean.

                        $objControl->AddAction(new QClickEvent(), new QAjaxControlAction($this,'btnToggleRecords_Click',$this->objParentObject->WaitIcon));
                    }

                    // We pass the parameter of "false" to make sure the control doesn't render
                    // itself RIGHT HERE - that it instead returns its string rendering result.
                    return $objControl->Render(false);
                }

                // Button press make other child QDataGrid Appear..
                public function btnToggleRecords_Click($strFormId, $strControlId, $strParameter) {

                    $srcControl = $this->Form->GetControl($strControlId);
                    $parControl = $srcControl->ParentControl;
                    $strType = $strParameter;

                    $objControlId = 'ucRecords' . $this->objDomain->Id . $strType;
                   
                    if ($objControl = $parControl->GetChildControl($objControlId)) {
                        if ($objControl->Visible) {
                            $objControl->Visible = false;
                            $srcControl->Text = '+';
                        } else {
                            $objControl->Visible = true;
                            $srcControl->Text = '-';
                        }
                       
                        // And refresh the Child QdataGrid this time...
                        $this->dtgRecordsSummary->Refresh();
                    }
                }

                // Create another child if you want... follow the same exactly
                // idea as applid in Master QdataGrid...
                public function render_ucRecords($parControl, $strType) {

                    $strControlId = 'ucRecords' . $this->objDomain->Id . $strType;

                    if (!$objControl = $parControl->GetChildControl($strControlId)) {

                        switch ($strType) {

                            case Records::A :
                                $objControl = new ARecordsList($this->dtgRecordsSummary, $this->objDomain, $strControlId);
                                break;

                            case Records::CNAME :
                                $objControl = new CNAMERecordsList($this->dtgRecordsSummary, $this->objDomain, $strControlId);
                                break;

                            case Records::MX :
                                $objControl = new MXRecordsList($this->dtgRecordsSummary, $this->objDomain, $strControlId);
                                break;

                            case Records::SRV :
                                $objControl = new SRVRecordsList($this->dtgRecordsSummary, $this->objDomain, $strControlId);
                               
                                break;

                            case Records::SPF :
                                $objControl = new SPFRecordsList($this->dtgRecordsSummary, $this->objDomain, $strControlId);
                                break;

                            default:
                                $objControl = new QDataGrid($parControl);
                                break;
                        }

                        $objControl->Visible = false;
                    }
                   
                    return $objControl->Render(false);
                }
        }
?>

As i say before the tpl.php file has a trick to show good we need to break the row of qdatagrid to show pretty and not break the html...

here is the code

        </td>
    </tr>
    <tr>
        <td colspan="6">
            <table border="0" cellpadding="0" cellspacing="0" width="100%">
                <tr>
                    <td><?php $_CONTROL->dtgRecordsSummary->Render(); ?></td>
                </tr>
            </table>
         </td>
    </tr>
    <tr>
        <td>

Well thats it, the QDataGrid, hope must be usefull for someone it was for me.

In next post gonna expand this and make it with inline editing.

Regards,

JMI