Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

nested tabs: javascript actions get wrongly executed for children when parents have bound actions #966

Open
koopa opened this issue May 9, 2016 · 2 comments

Comments

@koopa
Copy link
Contributor

koopa commented May 9, 2016

Description

I was experimenting around with lazy loading tabs in a nested tab setup and discovered that for example "tabsactivate" (QTabs_ActivateEvent) gets executed for all child tabs, even if it was bound to the parent tab only.

Fix

Below is a fix that works, but not sure if it's the right way nor the right place to do this.
Please review and share your thoughts.

--- a/includes/base_controls/_actions.inc.php
+++ b/includes/base_controls/_actions.inc.php
@@ -386,8 +386,14 @@
                                }
                        }

-                       return sprintf("qc.pA('%s', '%s', '%s#%s', %s, '%s');",
-                               $objControl->Form->FormId, $objControl->ControlId, get_class($this->objEvent), $this->strId, $this->getActionParameter($objControl), $strWaitIconControlId);
+                       $strCondition = '';
+                       if($objControl instanceof QTabs){
+                               $strCondition = 'if(event.target !== this){ return false; }';
+                       }
+                       $strReturn = sprintf("%s qc.pA('%s', '%s', '%s#%s', %s, '%s');",
+                               $strCondition, $objControl->Form->FormId, $objControl->ControlId, get_class($this->objEvent), $this->strId, $this->getActionParameter($objControl), $strWaitIconControlId);
+                       return $strReturn;
+
                }
        }

Simple test form + tmpl

nested_tab.php:

<?php
    require_once('qcubed.inc.php');
    class NestedTabForm extends QForm {
        /**
         * @var QTabs
         */
        protected $tabs;
        /**
         * @var QPanel
         */
        protected $log;
        /**
         * @var QPanel[]
         */
        protected $panels = [];

        protected function Form_Create() {
            $this->log = new QPanel($this);
            $this->tabs = new QTabs($this);
            $this->tabs->Headers = ['one', 'two'];
            $this->panels[] = $this->CreatePanel("hi", $this->tabs);
            $pnl = new QPanel($this->tabs);
            $pnl->AutoRenderChildren = true;
            $this->panels[] = $pnl;
            $tabs = new QTabs($this->panels[0]);
            $tabs->Headers = ['three', 'four'];
            $this->CreatePanel("aaa2", $tabs);
            $this->CreatePanel("bbb", $tabs);
            $this->tabs->AddAction(new QTabs_ActivateEvent(), new QAjaxAction('tabs_Load'));
        }

        public function CreatePanel($strContent, $objTab){
            $pnl = new QPanel($objTab);
            $pnl->AutoRenderChildren = true;
            $pnlContent = new QPanel($pnl);
            $pnlContent->Text = $strContent;
            return $pnl;
        }

        public function tabs_Load($strForm, $strControl, $strParam){
            /**
             * @var $objControl QTabs
             */
            $objControl = $this->GetControl($strControl);
            if(!$objControl){
                return;
            }
            $this->log->Text = $objControl->SelectedId.' activated';
            if($objControl->Active == 1){
                $pnlParent = $this->GetControl($objControl->SelectedId);
                if(count($pnlParent->GetChildControls()) > 0){
                    return;
                }
                $pnlContent = new QPanel($this->panels[1]);
                $pnlContent->Text = "there ";
                $this->tabs->Refresh();
            }
        }

    }
    NestedTabForm::Run('NestedTabForm', dirname(__FILE__).'/nested_tab.tpl.php');

nested_tab.tpl.php:

<?php $this->RenderBegin() ?>
<?php $this->log->Render(); ?>
<?php $this->tabs->Render(); ?>
<?php $this->RenderEnd() ?>
@olegabr olegabr added the bug label May 10, 2016
@spekary
Copy link
Member

spekary commented Jun 26, 2016

gets executed for all child tabs, even if it was bound to the parent tab only.

You have opened a big can of worms here. The problem is that the tabsactive event is bubbling up through the parent controls. The parent control is looking for the event, gets it from child controls, and so fires. It may be unexpected in this situation, but it is standard javascript behavior.

To change it could break code, and would be some effort. In other words, there are scenarios where someone wants this behavior. This is a much bigger issue than QTabs.

Possible fixes include:

  • Do nothing in the framework. You should set "event.target.id" as the Js Return Parameter of your action so that you can test what was clicked on and determine how to handle it.
  • Changing qcubed.js so that the target id of the control that was originally sent the event is always passed back to the event handler, so that you can test it.
  • Adding a parameter to QEvent that allows you to turn off bubbling. This would both make sure received bubbled events did not fire an event, and that any time an event fired off an ajax action, the event would no longer bubble to parent objects.

I think for now we leave this alone, and if it becomes a bigger issue we try one or a combination of the above.

Thoughts?

@spekary spekary added this to the 3.1 Release milestone Jun 26, 2016
@spekary
Copy link
Member

spekary commented Jun 26, 2016

Changing this to feature request since there is a workaround you can do without changing the framework.

@spekary spekary mentioned this issue Jun 28, 2016
@spekary spekary modified the milestones: 3.2 Release, 3.1 Release Mar 19, 2017
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Projects
None yet
Development

No branches or pull requests

3 participants