Thành phần lưới Magento không sắp xếp chính xác


16

Tôi đã cấu hình một thành phần lưới trong Magento - và hành vi sắp xếp có vẻ bị hỏng. Tôi có thể gỡ lỗi này ở cấp độ javascript ở đâu và / hoặc có ai khác biết tại sao điều này có thể xảy ra không?

Nếu tôi sắp xếp lưới một lần, yêu cầu ajax sẽ được thực hiện và mọi thứ sẽ được sắp xếp chính xác.

nhập mô tả hình ảnh ở đây

Tuy nhiên, loại thứ hai, không có yêu cầu ajax, sẽ hiển thị lưới với tất cả các ID giống nhau.

nhập mô tả hình ảnh ở đây

Hành vi không được lặp lại trên lưới lõi Magento, vì vậy tôi khá chắc chắn đây là việc tôi đang làm. Tôi chỉ không biết hệ thống thành phần ui đủ tốt để biết nơi bắt đầu gỡ lỗi này.

Câu trả lời:


21

Được rồi, tôi không thể giả vờ hiểu tại sao, nhưng vấn đề là datalập luận của tôi 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>
<!-- ... -->

Khi tôi so sánh điều này với một vài lưới lõi, datađối số bị thiếu một storageConfignút, với một indexFieldnút phụ có khóa chính của mô hình của tôi.

<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>

Khi tôi thêm các nút này, chức năng sắp xếp đã được khôi phục.


Chỉ gặp vấn đề tương tự, tôi tưởng tượng nó đang quay trở lại hoặc tải các giá trị từ bộ lưu trữ theo chỉ số hàng thay vì id hàng dữ liệu, mặc dù không có lý do tại sao dữ liệu bị trùng lặp. Cảm ơn bạn đã trả lời.
LM_Fielding

8

TL; DR

Đây thực sự là một vấn đề thú vị.

Đây là cách tôi hiểu hệ thống nhưng tôi có thể không đúng 100%.

Như bạn đã thấy, nhấp vào cột tiêu đề sẽ tạo một yêu cầu AJAX theo tuyến đường sau: /admin_key/mui/index/rendervới các tham số sau:

  • bộ lọc [giữ chỗ]
  • isAjax
  • không gian tên
  • phân trang [hiện tại]
  • phân trang [kích thước trang]
  • Tìm kiếm
  • sắp xếp [hướng]
  • sắp xếp [trường]

Cái cuối cùng là trường mà bạn đang sắp xếp lưới của mình.

Tuyến đường này được khai báo theo mặc định trong 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>

Nhưng trong một danh sách ui_component XML, nó cũng được khai báo:

        <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>

Tuyến này được xử lý app/code/Magento/Ui/Controller/Adminhtml/Index/Render.phpdựa trên tham số không gian tên (thường là tên của Thành phần UI của bạn)

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());
}

Trong đó prepareComponentphương thức được đệ quy trên các thành phần con:

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

Khi thành phần cột được chuẩn bị, việc sắp xếp cột được xử lý bởi 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();
}

Trong đó applySorting()phương thức dựa trên tham số sắp xếp và nó chỉ đơn giản là thêm thứ tự cho nhà cung cấp dữ liệu:

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'])
        );
    }
}

Khi mọi thành phần được chuẩn bị, lớp hành động sẽ kết xuất lại thành phần đó (một lần nữa đệ quy) cho phản hồi:

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

Tôi nghĩ đó là những bước quan trọng của PHP về những gì xảy ra trong quá trình sắp xếp.

Bây giờ với JS, các URL kết xuất và cập nhật (được khai báo ở definition.xmltrên) được gán cho phần tử trong 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 }'
        }
    }

Vẫn trong tệp này, có một requestDataphương thức được sử dụng để truy xuất dữ liệu 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);
    }

Bạn có thể thấy rằng phương thức này được gọi khi render()phương thức được gọi:

        $.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);
        });

Một khi điều này được thực hiện, một phương thức gọi lại được gọi để áp dụng dữ liệu. Đó là onRender():

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

Tôi nghĩ đó là nơi mà nội dung mới đang được áp dụng.


Mã Columbo ...
LM_Fielding
Khi sử dụng trang web của chúng tôi, bạn xác nhận rằng bạn đã đọc và hiểu Chính sách cookieChính sách bảo mật của chúng tôi.
Licensed under cc by-sa 3.0 with attribution required.