Magento网格组件未正确排序


16

我已经在Magento中配置了网格组件-排序行为似乎已损坏。我在哪里可以在javascript级别上调试它,和/或其他人不知道为什么会发生这种情况吗?

如果我对网格进行一次排序,则会发出ajax请求,并且一切都正确排序。

在此处输入图片说明

但是,第二种排序方法没有ajax请求,将使用所有相同的ID呈现网格。

在此处输入图片说明

在Magento核心网格上不会重复此行为,因此,我很确定这是我正在做的事情。我只是不太了解ui组件系统,所以不知道从哪里开始调试。

Answers:


21

好吧,我还不能假装理解为什么,但是问题出data在我的dataProvider论点上。

<!-- ... -->
<argument name="dataProvider" xsi:type="configurableObject">
    <!-- ... --->
    <argument name="data" xsi:type="array">
        <item name="config" xsi:type="array">
            <item name="update_url" xsi:type="url" path="mui/index/render"/>
        </item>
    </argument>
    <!-- ... -->
</argument>
<!-- ... -->

当我将其与几个核心网格进行比较时,该data参数缺少一个storageConfig节点,该节点带有一个indexField具有我的模型主键的子节点。

<argument name="data" xsi:type="array">
    <item name="config" xsi:type="array">
        <item name="update_url" xsi:type="url" path="mui/index/render"/>
        <item name="storageConfig" xsi:type="array">
            <item name="indexField" xsi:type="string">pulsestorm_commercebug_log_id</item>
        </item>                    

    </item>                          
</argument>

当我添加这些节点时,排序功能得以恢复。


只是遇到了同样的问题,我想这是回退或通过行索引而不是数据行ID从存储中加载值,尽管为什么没有重复数据是没有道理的。谢谢你的回答。
LM_Fielding

7

TL; DR

这确实是一个有趣的问题。

这是我对系统的理解,但我可能不是100%正确。

如您所见,单击标题列会向以下路由生成AJAX请求:/admin_key/mui/index/render具有以下参数:

  • 过滤器[占位符]
  • isAjax
  • 命名空间
  • 分页[当前]
  • 分页[pageSize]
  • 搜索
  • 排序[方向]
  • 排序[字段]

最后一个是要对网格进行排序的字段。

默认情况下,此路由在中声明app/code/Magento/Ui/view/base/ui_component/etc/definition.xml

<insertListing class="Magento\Ui\Component\Container">
    <argument name="data" xsi:type="array">
        <item name="config" xsi:type="array">
            <item name="component" xsi:type="string">Magento_Ui/js/form/components/insert-listing</item>
            <item name="update_url" xsi:type="url" path="mui/index/render"/>
            <item name="render_url" xsi:type="url" path="mui/index/render"/>
            <item name="autoRender" xsi:type="boolean">false</item>
            <item name="dataLinks" xsi:type="array">
                <item name="imports" xsi:type="boolean">true</item>
                <item name="exports" xsi:type="boolean">false</item>
            </item>
            <item name="realTimeLink" xsi:type="boolean">true</item>
        </item>
    </argument>
</insertListing>

但是在清单ui_component XML中也声明了它:

        <argument name="data" xsi:type="array">
            <item name="config" xsi:type="array">
                <item name="component" xsi:type="string">Magento_Ui/js/grid/provider</item>
                <item name="update_url" xsi:type="url" path="mui/index/render"/>
                <item name="storageConfig" xsi:type="array">
                    <item name="indexField" xsi:type="string">page_id</item>
                </item>
            </item>
        </argument>

该路由是app/code/Magento/Ui/Controller/Adminhtml/Index/Render.php根据名称空间参数(通常是您的UI组件的名称)处理的

public function execute()
{
    if ($this->_request->getParam('namespace') === null) {
        $this->_redirect('admin/noroute');
        return;
    }

    $component = $this->factory->create($this->_request->getParam('namespace'));
    $this->prepareComponent($component);
    $this->_response->appendBody((string) $component->render());
}

prepareComponent方法是在子组件递归:

protected function prepareComponent(UiComponentInterface $component)
{
    foreach ($component->getChildComponents() as $child) {
        $this->prepareComponent($child);
    }
    $component->prepare();
}

准备好列组件后,可通过以下方式处理列排序app/code/Magento/Ui/Component/Listing/Columns/Column.php

public function prepare()
{
    $this->addFieldToSelect();

    $dataType = $this->getData('config/dataType');
    if ($dataType) {
        $this->wrappedComponent = $this->uiComponentFactory->create(
            $this->getName(),
            $dataType,
            array_merge(['context' => $this->getContext()], (array) $this->getData())
        );
        $this->wrappedComponent->prepare();
        $wrappedComponentConfig = $this->getJsConfig($this->wrappedComponent);
        // Merge JS configuration with wrapped component configuration
        $jsConfig = array_replace_recursive($wrappedComponentConfig, $this->getJsConfig($this));
        $this->setData('js_config', $jsConfig);

        $this->setData(
            'config',
            array_replace_recursive(
                (array)$this->wrappedComponent->getData('config'),
                (array)$this->getData('config')
            )
        );
    }

    $this->applySorting();

    parent::prepare();
}

applySorting()方法基于sorting参数,并且只需将订单添加到数据提供程序即可:

protected function applySorting()
{
    $sorting = $this->getContext()->getRequestParam('sorting');
    $isSortable = $this->getData('config/sortable');
    if ($isSortable !== false
        && !empty($sorting['field'])
        && !empty($sorting['direction'])
        && $sorting['field'] === $this->getName()
    ) {
        $this->getContext()->getDataProvider()->addOrder(
            $this->getName(),
            strtoupper($sorting['direction'])
        );
    }
}

一旦准备好每个组件,操作类就会(再次递归)呈现该组件以响应:

$this->_response->appendBody((string) $component->render());

我认为这些是排序过程中重要的PHP步骤。

现在到JS,渲染和更新URL(在definition.xml上面声明)被分配给元素app/code/Magento/Ui/view/base/web/js/form/components/insert.js

return Element.extend({
    defaults: {
        content: '',
        template: 'ui/form/insert',
        showSpinner: true,
        loading: false,
        autoRender: true,
        visible: true,
        contentSelector: '${$.name}',
        externalData: [],
        params: {
            namespace: '${ $.ns }'
        },
        renderSettings: {
            url: '${ $.render_url }',
            dataType: 'html'
        },
        updateSettings: {
            url: '${ $.update_url }',
            dataType: 'json'
        },
        imports: {},
        exports: {},
        listens: {},
        links: {
            value: '${ $.provider }:${ $.dataScope}'
        },
        modules: {
            externalSource: '${ $.externalProvider }'
        }
    }

仍然在此文件中,有一种requestData方法可用于检索AJAX数据:

    requestData: function (params, ajaxSettings) {
        var query = utils.copy(params);

        ajaxSettings = _.extend({
            url: this['update_url'],
            method: 'GET',
            data: query,
            dataType: 'json'
        }, ajaxSettings);

        this.loading(true);

        return $.ajax(ajaxSettings);
    }

您可以看到在调用该render()方法时调用了该方法:

        $.async({
            component: this.name,
            ctx: '.' + this.contentSelector
        }, function (el) {
            self.contentEl = $(el);
            self.startRender = true;
            params = _.extend({}, self.params, params || {});
            request = self.requestData(params, self.renderSettings);
            request
                .done(self.onRender)
                .fail(self.onError);
        });

完成此操作后,将调用回调方法以应用数据。是onRender()

    onRender: function (data) {
        this.loading(false);
        this.set('content', data);
        this.isRendered = true;
        this.startRender = false;
    }

我认为这就是应用新内容的地方。


代码哥伦布...
LM_Fielding
By using our site, you acknowledge that you have read and understand our Cookie Policy and Privacy Policy.
Licensed under cc by-sa 3.0 with attribution required.