Using 2.1.3, I am loading admin tab content by calling a block directly in the Tabs.php
file:
protected function _beforeToHtml()
{
$blockClass = "MyNamespace\MyModule\Block\Adminhtml\Section\Edit\Tabs\BlockClassName";
$this->addTab(
'tab_title',
[
'label' => __('Tab Label'),
'title' => __('Tab Title'),
'content' => $this->getLayout()->createBlock($blockClass)->toHtml(),
'active' => true
]
);
}
Within the template phtml file I've set in the BlockClassName.php
file, I'd like to use $block->getChildHtml('child_block_name')
.
I've tried using the addChild
(per Adding a Child Block Programmatically) to the BlockClassName::_construct()
, but am getting an error:
vendor/magento/framework/Data/Structure.php(603): Magento\Framework\Data\Structure->_assertElementExists(NULL);
Where it looks like the vendor/magento/framework/View/Element/AbstractBlock::setChild()
is trying to pass in the block's layout name (line 380) – do I need to define the block in a layout in order to add a child block?
Best Answer
No. Magento uses one central layout tree, not multiple depending where they are defined. However, if you look in
\Magento\Framework\View\Layout\Generator\Block::createBlock()
, you'll notice that the block is created (and the constructors are called) before the name is set:The
getBlockInstance()
method creates the block and calls the constructors. Then, the name is set.Next, the block is set in layout, in the
\Magento\Framework\View\Layout\Generator\Block::process()
method. Later on in that method, thesetLayout()
method is called on each block, which provides the block with an instance ofMagento\Framework\View\Layout
and calls the_prepareLayout()
method on each block. The right place to set children is inside your block's_prepareLayout()
method, since this will be called after the name is set, the block is set in layout, and the block has a reference to the layout object.I'd do it like this:
Please let me know if you have any questions!