QDialogBox within QPanel cannot create controls

Login or register to post comments
12 replies [Last post]
Offline
Joined: 06/02/2010

I have a perplexing issue where I'm getting the following error:

Fatal error: Call to a member function AddControl() on a non-object in /includes/qcubed/_core/base_controls/QControlBase.class.php on line 183

I have the following setup:

  • a QForm that creates two QPanels
  • One of the QPanels creates a QDialogBox
  • The QDialogBox creates a MetaControl class.

Everything works perfect up to this point.

The MetaControl class then tries to create a QLabel and this is when the error occurs. (It's the first control to be created).

I have verified that all objects leading up to this point are created correctly and the ParentObject passed to the QLabel constructor exists. I'm thinking that somewhere in here there's an issue with something being "protected" instead of "public"? I'm not totally clued into what the core is doing here with this complex scenario.

Any thoughts off the top of your head why this error might happen?

alex94040's picture
Offline
Joined: 11/06/2008

Can you post a code snippet, please?

Offline
Joined: 06/02/2010

Lots of code (not really a "snippet") but here's what I've got. I've the path of code that fails with comments.

QForm

class FeedItemShow extends QForm {

   protected $FeedItemPanel;
   protected $ShowEditPanel;

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

      $intSyndicatedFeedId = QApplication::PathInfo(0);
      $this->FeedItemPanel =
         new SyndicatedFeedItemViewPanel($this,
             null,
             $intSyndicatedFeedId);
      $this->ShowEditPanel =
            new ShowEditPanel($this, null, null); // Error Path
   }
}

QPanel

class ShowEditPanel extends QPanel {
   protected $mctShow;
   public $lstProfileOrganization;
   public $btnOrg;
   public $OrgEditDialog;

   public function __construct($objParentObject,
          $strClosePanelMethod,
          $intShowId = null,
          $strControlId = null) {
      try {
         parent::__construct($objParentObject, $strControlId);
      } catch (QCallerException $objExc) {
         $objExc->IncrementOffset();
         throw $objExc;
      }

      $this->strTemplate = __DOCROOT__ . 
         '/show/template/ShowEditPanel.tpl.php';
      $this->strClosePanelMethod = $strClosePanelMethod;

      $this->mctShow = ShowMetaControl::Create($this, $intShowId);

      $this->lstProfileOrganization =
         $this->mctShow->lstProfileOrganization_Create();
      $this->lstProfileOrganization->Name =
         QApplication::Translate('Organization');

      $this->btnOrg = new QButton($this);
      $this->btnOrg->Text = QApplication::Translate('New');
      $this->btnOrg->AddAction(new QClickEvent(),
         new QAjaxAction('btnOrg_Click'));

      $this->OrgEditDialog =
         new ProfileOrganizationEditDialog($this,
         'btnOrg_Close'); // Error Path
      $this->OrgEditDialog->Display = false;

   }

   protected function btnOrg_Click($strFormId,
         $strControlId, $strParameter) {
      $this->OrgEditDialog->ShowDialogBox();
   }

   public function btnOrg_Close($strFormId,
         $strControlId, $strParameter) {
      $this->lstProfileOrganization->SelectedValue =
         $this->OrgEditDialog->ProfileOrganizationId;
   }
}

QDialogBox

class ProfileOrganizationEditDialog extends QDialogBox {
   public $mctProfileOrganization;
   public $lblProfileOrganizationId;
   public $btnSave;

   public function __construct($objParentObject,
      $strClosePanelMethod,
      $intProfileOrganizationId = null,
      $strControlId = 'OrgEditDialog') {
      try {
         parent::__construct($objParentObject, $strControlId);
      } catch (QCallerException $objExc) {
         $objExc->IncrementOffset();
         throw $objExc;
      }

      $this->strTemplate = __DOCROOT__  .
         '/org/template/ProfileOrganizationEditDialog.tpl.php';
      $this->strClosePanelMethod = $strClosePanelMethod;
      $this->CssClass = 'orgEditDialog';
      $this->blnMatteClickable = false;

      $this->mctProfileOrganization =
         ProfileOrganizationMetaControl::Create($this,
            $intProfileOrganizationId);

      // Error Path
      $this->lblProfileOrganizationId =
         $this->mctProfileOrganization->lblProfileOrganizationId_Create();

      $this->btnSave = new QButton($this);
      $this->btnSave->Text = QApplication::Translate('Save');
      $this->btnSave->AddAction(new QClickEvent(),
         new QAjaxControlAction($this, 'btnSave_Click'));
      $this->btnSave->CausesValidation = $this;
   }


   public function btnSave_Click($strFormId, $strControlId,
         $strParameter) {
      $this->mctProfileOrganization->SaveProfileOrganization();
      $this->HideDialogBox();
   }
}

MetaControl

class ProfileOrganizationMetaControl extends
   ProfileOrganizationMetaControlGen {

   public function lblProfileOrganizationId_Create(
      $strControlId = 'lblProfileOrganizationId') {

      // Error Generated by this line
      $this->lblProfileOrganizationId =
         new QLabel($this->objParentObject, $strControlId);
      $this->lblProfileOrganizationId->Name =
         QApplication::Translate('Profile Organization Id');
      if ($this->blnEditMode)
         $this->lblProfileOrganizationId->Text =
         $this->objProfileOrganization->ProfileOrganizationId;
      else
         $this->lblProfileOrganizationId->Text = 'N/A';
      return $this->lblProfileOrganizationId;
   }
}

Offline
Joined: 06/02/2010

So I looked through the code in QControlBase.class.php. The line of code is as follows:

$this->strControlId = $this->objForm->GenerateControlId();

So I'm gathering from this code that the nesting of objects doesn't pass down a handle to the Form object.

It's so perplexing because I have verified the QDialogBox has a handle the Form, but for some reason it gets to this point and then says 'object doesn't exist' even though it's right there! Argh!

Any idea how to resolve this?

Steven Warren's picture
Offline
Joined: 11/06/2008

Is OrgEditDialog rendered in your "__DOCROOT__ . '/show/template/ShowEditPanel.tpl.php';" template?

cliff's picture
Offline
Joined: 04/11/2008

I have a similar issue. I have a form that has a button that shows a QDialogBox. The QDialogBox has a metacontrol.

This works fine _if_ I create the metacontrol with CreateFromPathInfo($this); If I just use Create($this), then several things break, like actions don't fire on buttons on my main form, and I can't actually use the metacontrol in the QDialogBox to create new objects.

The dialog still shows in both cases and the metacontrol renders, but there is an error somewhere.

cliff's picture
Offline
Joined: 04/11/2008

I'm using 2.0.1 and there is definitely something very strange going on. I've been trying to track down the bug for a good 6 hours now and can't seem to find out where it is going wrong.

For me, if I put controls in a QDialogBox it works fine, but if I put a metacontrol in the QDialogBox, then weird things start to happen, like a button on my form doesn't respond to actions anymore.

I have narrowed it down though so that this only happens if the metacontrol has a control on it that is marked as 'required'. So now I suspect it has something to do with form validation.

So, if you have a QDialogBox with a metacontrol on it that has, say, a selectbox that is marked as 'required', then a button on my main form does not seem to fire. Actually, I am assuming it is firing but failing validation in some way but I can't see the validation message because the QdialogBox is hidden.

After many hours of banging heads and tearing hair, I found a solution.

My QdialogBox has code like this:

      $this->dlgAddTask = new AddTaskDialog('btnAddTask_Close', $this);
      $this->dlgAddTask->Title = "Add a Task";     
      $this->dlgAddTask->Display = false;

This is straight from the examples site.

Now the Qcubed validation rules should only apply to visible controls ( according to the examples site), but actually, the ->Display() function is not the right one for that, because this makes it work:

      $this->dlgAddTask = new AddTaskDialog('btnAddTask_Close', $this);
      $this->dlgAddTask->Title = "Add a Task";
      $this->dlgAddTask->Visible = false;
      $this->dlgAddTask->Display = false;

So the underlying issue for me was that ->Visible and ->Display do similar but not identical things. I assume this is due to the way that most of the jqueryUI component code was automatically generated and a small change needs to be made to the ->Display() function.

Your problem is probably different than mine, but perhaps this helps.

Offline
Joined: 06/02/2010

it's really weird that adding "Visible = false" would correct an issue like this. "Display" should be more destructive than "Visible".

"Visible" is more benign because it actually leaves the control on the page, just hides it. "Display" removes the control from the page (I guess you could say).

Your fix leads me to believe there is some glitch for how this information is inherits through the control hierarchy. Definitely a different issue that mine, but still related to inheritance. Glad you were able to find a workaround.

Offline
Joined: 03/31/2008

Actually, I think you have that reversed. Display controls the CSS to hide elements, while Visible controls whether the element is sent to the client at all.

Obviously invisible controls should not be validated. But non-displayed ones may be.

Offline
Joined: 06/02/2010

ha ha, you're correct, I clearly need more coffee before I type sometimes. Correct, and this is probably why he's no longer getting a validation error (since he added the "visible=false" which removed the control from the page.

thanks for the correction!

cliff's picture
Offline
Joined: 04/11/2008

The problem is a bit deeper. If I dismiss the dialog box with parent::HideDialogBox(), say, by hitting a cancel button, my form breaks again. I even tried to create the dialog box with an explicit Cancel callback function set, so when the cancel button is clicked, my main form gets to execute the cancel callback and I explicitly set both visible and display to false in that callback, but my button won't fire after that, which I assume still has something to do with validation.

Setting my button on my main form to $this->btnEdit->CausesValidation = false; also doesn't seem to work, although you would think that would do it. The button works when the form first loads, and it still works if I launch the dialog box and fill in the form that is in it and hit 'save'. But if I launch the dialog and hit 'Cancel' to dismiss it without setting any of the values, then my btnEdit button doesn't work anymore.

Offline
Joined: 03/31/2008

Buttons failing to fire events is rarely a cause of bad PHP, but rather of the browser refusing to run the javascript anymore. This is usually due to a javascript crash earlier in the page cycle (such as after the Save button is hit). Try debugging your javascript and see if that gives any clues.

vakopian's picture
Offline
Joined: 04/08/2008

Cliff,

Since you mentioned "I assume this is due to the way that most of the jqueryUI component code was automatically generated..."

I wanted to point out that QDialogBox is not one of the auto-generated controls (the auto-generated one is actually called QDialog). QDialogBox is the hand-coded old version that has been ported to jQuery in 2.x.