Componente griglia Magento non ordinato correttamente


16

Ho configurato un componente griglia in Magento e il comportamento di ordinamento sembra non funzionare. Dove posso eseguire il debug a livello di JavaScript e / o qualcun altro ha idea del perché ciò potrebbe accadere?

Se ordino una volta la griglia, viene fatta una richiesta Ajax, e tutto si ordina correttamente.

inserisci qui la descrizione dell'immagine

Tuttavia, il secondo ordinamento, senza una richiesta Ajax, esegue il rendering della griglia con tutti gli stessi ID.

inserisci qui la descrizione dell'immagine

Il comportamento non si ripete sulle griglie core di Magento, quindi sono abbastanza sicuro che sia qualcosa che sto facendo. Semplicemente non conosco abbastanza bene il sistema di componenti dell'interfaccia utente per sapere da dove iniziare il debug.

Risposte:


21

Va bene, non posso ancora fingere di capire perché, ma il problema era l' dataargomento della mia dataProviderdiscussione.

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

Quando l'ho confrontato con alcune delle griglie principali, dataall'argomento mancava un storageConfignodo, con un indexFieldsotto-nodo con la chiave primaria del mio modello.

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

Quando ho aggiunto questi nodi, la funzionalità di ordinamento è stata ripristinata.


Ho appena riscontrato lo stesso problema, immagino che stia ricadendo o caricando i valori dalla memoria dall'indice di riga anziché dall'ID della riga di dati, anche se non ha senso il motivo per cui i dati sono duplicati. Grazie per la risposta.
LM_Fielding

7

TL; DR

Questo è davvero un problema interessante.

Ecco come ho capito il sistema ma potrei non avere ragione al 100%.

Come hai visto, fare clic sulla colonna di intestazione genera una richiesta AJAX per la seguente route: /admin_key/mui/index/rendercon i seguenti parametri:

  • filtri [placeholder]
  • isAjax
  • namespace
  • paginazione [corrente]
  • paginazione [pageSize]
  • ricerca
  • smistamento [direzione]
  • l'ordinamento [campo]

L'ultimo è il campo su cui stai ordinando la griglia.

Questo percorso è dichiarato per impostazione predefinita in 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>

Ma in un elenco ui_component XML è anche dichiarato:

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

Questa route viene gestita in app/code/Magento/Ui/Controller/Adminhtml/Index/Render.phpbase al parametro namespace (che è normalmente il nome del componente 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());
}

Dove il prepareComponentmetodo è ricorsivo sui componenti figlio:

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

Quando viene preparato il componente colonna, l'ordinamento delle colonne viene gestito da 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();
}

Dove il applySorting()metodo si basa sul parametro di ordinamento e aggiunge semplicemente l'ordine al fornitore di dati:

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

Una volta preparato ogni componente, la classe di azione esegue il rendering del componente (di nuovo in modo ricorsivo) per la risposta:

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

Ritengo che questi siano gli importanti passaggi PHP di ciò che accade durante l'ordinamento.

Ora a JS, gli URL di rendering e aggiornamento (dichiarati definition.xmlsopra) sono assegnati all'elemento in 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 }'
        }
    }

Sempre in questo file, esiste un requestDatametodo utilizzato per recuperare i dati 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);
    }

Puoi vedere che questo metodo viene chiamato quando viene chiamato il render()metodo:

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

Fatto ciò, viene chiamato un metodo di callback per applicare i dati. È onRender():

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

Credo che sia qui che viene applicato il nuovo contenuto.


Codice Columbo ...
LM_Fielding
Utilizzando il nostro sito, riconosci di aver letto e compreso le nostre Informativa sui cookie e Informativa sulla privacy.
Licensed under cc by-sa 3.0 with attribution required.