마 젠토 그리드 구성 요소가 올바르게 정렬되지 않음


16

Magento에서 그리드 구성 요소를 구성했는데 정렬 동작이 깨져 보입니다. 자바 스크립트 수준에서 이것을 디버깅 할 수있는 곳 및 / 또는 다른 사람이 왜 이런 일이 일어날 지 알고 있습니까?

그리드를 한 번 정렬하면 아약스 요청이 이루어지고 모든 것이 올바르게 정렬됩니다.

여기에 이미지 설명을 입력하십시오

그러나 두 번째 정렬은 아약스 요청없이 모두 동일한 ID를 가진 그리드를 렌더링합니다.

여기에 이미지 설명을 입력하십시오

Magento 코어 그리드에서 동작이 반복 되지 않으므로 이것이 내가하고있는 일이라고 확신합니다. 나는 단지 디버깅을 시작할 곳을 알 수있을 정도로 ui 구성 요소 시스템을 잘 모른다.

답변:


21

좋아, 아직 이유를 이해하는 척 할 수는 없지만 문제는 datadataProvider주장의 주장이었다.

<!-- ... -->
<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 % 정확하지 않을 수 있습니다.

헤더 열을 클릭하면 /admin_key/mui/index/render다음 매개 변수와 함께 다음 경로에 대한 AJAX 요청이 생성 됩니다.

  • 필터 [자리 표시 자]
  • 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();
}

를 Where applySorting()방법은 정렬 매개 변수를 기반으로 단순히 데이터 공급자 순서를 추가한다 :

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

이 파일에는 여전히 requestDataAJAX 데이터를 검색하는 데 사용되는 메소드가 있습니다.

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

나는 그것이 새로운 내용이 적용되는 곳이라고 생각합니다.


Code Columbo ...
LM_Fielding
당사 사이트를 사용함과 동시에 당사의 쿠키 정책개인정보 보호정책을 읽고 이해하였음을 인정하는 것으로 간주합니다.
Licensed under cc by-sa 3.0 with attribution required.