Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

magento2: loading an uicomponent with Ajax

I've been struggling with that for days... For an admin extension, I'm trying to load an uiComponent with Ajax to be displayed in a tab. The uiComponent is correctly loaded but seems not to be fully processed by client-side knockout logic.

namespace Man4x\MondialRelay2\Block\Adminhtml\Shipping;

class Tabs
extends \Magento\Backend\Block\Widget\Tabs {
protected function _construct()
{
    parent::_construct();
    $this->setId('mondialrelay2_shipping_tabs');
    $this->setDestElementId('container');
    $this->setTitle(__('MondialRelay'));
} 

protected function _beforeToHtml()
{
    $this->addTab(
        'mass_shipping',
        [
            'label' => __('Mass Shipping'),
            'title' => __('Mass Shipping'),
            'url'   => $this->getUrl('*/*/massshipping', ['_current' => true]),
            'class'  => 'ajax'
        ]
    );

    return parent::_beforeToHtml();
}
}

Here is the simple controller layout:

<?xml version="1.0"?>

<page xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:noNamespaceSchemaLocation="urn:magento:framework:View/Layout/etc/page_configuration.xsd">
<container name="root" label="Root">
    <uiComponent name="mondialrelay2_massshipping_grid"/>
</container>

Note: this custom uiComponent is perfectly functional when loaded in a standard (i.e. non-AJAX) way

When tracking out AJAX response, I can see the correct HTML code for the uiComponent is loaded (included the Magento specific "x-magento-init" tag). It's then processed by the jquery-ui callback:

    this.xhr = $.ajax( this._ajaxSettings( anchor, event, eventData ) );

    // support: jQuery <1.8
    // jQuery <1.8 returns false if the request is canceled in beforeSend,
    // but as of 1.8, $.ajax() always returns a jqXHR object.
    if ( this.xhr && this.xhr.statusText !== "canceled" ) {
        tab.addClass( "ui-tabs-loading" );
        panel.attr( "aria-busy", "true" );

        this.xhr
            .success(function( response ) {
                // support: jQuery <1.8
                // http://bugs.jquery.com/ticket/11778
                setTimeout(function() {
                    panel.html( response );
                    that._trigger( "load", event, eventData );
                }, 1 );
            })

...for loaded HTML code to be inserted in the container tag. Then, a bunch of callbacks and hooks are processed in the js modules jungle. A "contentUpdated" event is finally triggered, causing the:

/**
 * Init components inside of dynamically updated elements
 */
$('body').on('contentUpdated', function () {
    if (mage) {
        mage.apply();
    }
});

return $.mage;
}));

mage/apply/main.js and mage/apply/scripts.js are then correctly called (as tracked down in the browser console) but... nothing happens. My loaded

<script type="x-magento-init">

disappeared but my component JS logic doesn't process at all.

Any enlightenment would be highly appreciated.

PS: after deeper investigation, it seems that component JS files of the uiComponent are actually loaded, but not their templates !

like image 636
Man4x Avatar asked Nov 08 '22 02:11

Man4x


1 Answers

I encountered the same problem you did in a similar scenario. It seems like the bindings are not applied as they should, or at least not when they should, in this scenario. To fix it without altering the template i resorted to some additional xml, in your case this could be:

<?xml version="1.0"?>
<page xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:noNamespaceSchemaLocation="urn:magento:framework:View/Layout/etc/page_configuration.xsd">
<container name="root" label="Root" htmlTag="div" htmlId="mondialrelay2">
    <uiComponent name="mondialrelay2_massshipping_grid"/>
    <block class="Magento\Framework\View\Element\Text" name="ajax_ui_component_fix">
        <action method="setText">
            <argument name="text" xsi:type="string"><![CDATA[<script>
                require(['jquery'], function ($) {
                    $('#mondialrelay2').applyBindings();
                });
            </script>]]></argument>
        </action>
    </block>
</container>
like image 53
uiComponentLover666 Avatar answered Nov 15 '22 11:11

uiComponentLover666