2

We have products in our magento 2 store with more than 50 options added to each of customizable option. It takes much time to go to next page.

Can we remove the pagination or a way to increase it to 50(currently its 20 per page)?

2 Answers 2

0

If you want to increase the pagination for Customizable Options (backend) need to override dynamic-rows.js from below path.

magento/vendor/magento/module-ui/view/base/web/js/dynamic-rows.js

Create custom module to override dynamic-rows.js and and increase the pagination pageSize as you want.

File path: magento/app/code/Vendor/AdmincustomPagination/registration.php

<?php

use \Magento\Framework\Component\ComponentRegistrar;

ComponentRegistrar::register(ComponentRegistrar::MODULE, 'Vendor_AdmincustomPagination', __DIR__);

File path: magento/app/code/Vendor/AdmincustomPagination/etc/module.xml

<?xml version="1.0"?>

<config xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:noNamespaceSchemaLocation="urn:magento:framework:Module/etc/module.xsd">
    <module name="Vendor_AdmincustomPagination" setup_version="1.0.0">
    </module>
</config>

File path: magento/app/code/Vendor/AdmincustomPagination/view/adminhtml/requirejs-config.js

var config = {
    "map": {
        "*": {
            "Magento_Ui/js/dynamic-rows/dynamic-rows": "Vendor_AdmincustomPagination/js/dynamic-rows/dynamic-rows",
        }
    }
}

File path: magento/app/code/Vendor/AdmincustomPagination/view/adminhtml/web/js/dynamic-rows/dynamic-rows.js

define([
    'ko',
    'mageUtils',
    'underscore',
    'uiLayout',
    'uiCollection',
    'uiRegistry',
    'mage/translate'
], function (ko, utils, _, layout, uiCollection, registry, $t) {
    'use strict';

    return uiCollection.extend({
        defaults: {
            defaultRecord: false,
            columnsHeader: true,
            columnsHeaderAfterRender: false,
            columnsHeaderClasses: '',
            labels: [],
            recordTemplate: 'record',
            collapsibleHeader: false,
            additionalClasses: {},
            visible: true,
            disabled: false,
            fit: false,
            addButton: true,
            addButtonLabel: $t('Add'),
            recordData: [],
            maxPosition: 0,
            deleteProperty: 'delete',
            identificationProperty: 'record_id',
            deleteValue: true,
            showSpinner: true,
            isDifferedFromDefault: false,
            defaultState: [],
            defaultPagesState: {},
            pagesChanged: {},
            hasInitialPagesState: {},
            changed: false,
            fallbackResetTpl: 'ui/form/element/helper/fallback-reset-link',
            dndConfig: {
                name: '${ $.name }_dnd',
                component: 'Magento_Ui/js/dynamic-rows/dnd',
                template: 'ui/dynamic-rows/cells/dnd',
                recordsProvider: '${ $.name }',
                enabled: true
            },
            templates: {
                record: {
                    parent: '${ $.$data.collection.name }',
                    name: '${ $.$data.index }',
                    dataScope: '${ $.$data.collection.index }.${ $.name }',
                    nodeTemplate: '${ $.parent }.${ $.$data.collection.recordTemplate }'
                }
            },
            links: {
                recordData: '${ $.provider }:${ $.dataScope }.${ $.index }'
            },
            listens: {
                visible: 'setVisible',
                disabled: 'setDisabled',
                childTemplate: 'initHeader',
                recordTemplate: 'onUpdateRecordTemplate',
                recordData: 'setDifferedFromDefault parsePagesData setRecordDataToCache',
                currentPage: 'changePage',
                elems: 'checkSpinner',
                changed: 'updateTrigger'
            },
            modules: {
                dnd: '${ $.dndConfig.name }'
            },
            pages: 1,
            pageSize: 200,
            relatedData: [],
            currentPage: 1,
            recordDataCache: [],
            startIndex: 0
        },

        setRecordDataToCache: function (data) {
            this.recordDataCache = data;
        },

        initialize: function () {
            _.bindAll(this,
                'processingDeleteRecord',
                'onChildrenUpdate',
                'checkDefaultState',
                'renderColumnsHeader',
                'deleteHandler',
                'setDefaultState'
            );

            this._super()
                .initChildren()
                .initDnd()
                .initDefaultRecord()
                .setInitialProperty()
                .setColumnsHeaderListener()
                .checkSpinner();

            this.on('recordData', this.checkDefaultState);

            return this;
        },

        bubble: function (event) {
            if (event === 'deleteRecord' || event === 'update') {
                return false;
            }

            return this._super();
        },

        initDnd: function () {
            if (this.dndConfig.enabled) {
                layout([this.dndConfig]);
            }

            return this;
        },

        destroy: function () {
            if (this.dnd()) {
                this.dnd().destroy();
            }
            this._super();
        },

        initObservable: function () {
            this._super()
                .track('childTemplate')
                .observe([
                    'pages',
                    'currentPage',
                    'recordData',
                    'columnsHeader',
                    'visible',
                    'disabled',
                    'labels',
                    'showSpinner',
                    'isDifferedFromDefault',
                    'changed'
                ]);

            return this;
        },

        initElement: function (elem) {
            this._super();
            elem.on({
                'deleteRecord': this.deleteHandler,
                'update': this.onChildrenUpdate,
                'addChild': this.setDefaultState
            });

            return this;
        },

        deleteHandler: function (index, id) {
            var defaultState;

            this.setDefaultState();
            defaultState = this.defaultPagesState[this.currentPage()];
            this.processingDeleteRecord(index, id);
            this.pagesChanged[this.currentPage()] =
                !compareArrays(defaultState, this.arrayFilter(this.getChildItems()));
            this.changed(_.some(this.pagesChanged));
        },

        setInitialProperty: function () {
            if (_.isArray(this.recordData())) {
                this.recordData.each(function (data, index) {
                    this.source.set(this.dataScope + '.' + this.index + '.' + index + '.initialize', true);
                }, this);
            }

            return this;
        },

        onChildrenUpdate: function (state) {
            var changed,
                dataScope,
                changedElemDataScope;

            if (state && !this.hasInitialPagesState[this.currentPage()]) {
                this.setDefaultState();
                changed = this.getChangedElems(this.elems());
                dataScope = this.elems()[0].dataScope.split('.');
                dataScope.splice(dataScope.length - 1, 1);
                changed.forEach(function (elem) {
                    changedElemDataScope = elem.dataScope.split('.');
                    changedElemDataScope.splice(0, dataScope.length);
                    changedElemDataScope[0] =
                        (parseInt(changedElemDataScope[0], 10) - this.pageSize * (this.currentPage() - 1)).toString();
                    this.setValueByPath(
                        this.defaultPagesState[this.currentPage()],
                        changedElemDataScope, elem.initialValue
                    );
                }, this);
            }

            if (this.defaultPagesState[this.currentPage()]) {
                this.setChangedForCurrentPage();
            }
        },

        setDefaultState: function (data) {
            var componentData,
                childItems;

            if (!this.hasInitialPagesState[this.currentPage()]) {
                childItems = this.getChildItems();
                componentData = childItems.length ?
                    utils.copy(childItems) :
                    utils.copy(this.getChildItems(this.recordDataCache));
                componentData.forEach(function (dataObj) {
                    if (dataObj.hasOwnProperty('initialize')) {
                        delete dataObj.initialize;
                    }
                });

                this.hasInitialPagesState[this.currentPage()] = true;
                this.defaultPagesState[this.currentPage()] = data ? data : this.arrayFilter(componentData);
            }
        },

        setValueByPath: function (obj, path, value) {
            var prop;

            if (_.isString(path)) {
                path = path.split('.');
            }

            if (path.length - 1) {
                prop = obj[path[0]];
                path.splice(0, 1);
                this.setValueByPath(prop, path, value);
            } else if (path.length && obj) {
                obj[path[0]] = value;
            }
        },

        getChangedElems: function (array, changed) {
            changed = changed || [];

            array.forEach(function (elem) {
                if (_.isFunction(elem.elems)) {
                    this.getChangedElems(elem.elems(), changed);
                } else if (_.isFunction(elem.hasChanged) && elem.hasChanged()) {
                    changed.push(elem);
                }
            }, this);

            return changed;
        },

        setColumnsHeaderListener: function () {
            if (this.columnsHeaderAfterRender) {
                this.on('recordData', this.renderColumnsHeader);

                if (_.isArray(this.recordData()) && this.recordData().length) {
                    this.renderColumnsHeader();
                }
            }

            return this;
        },

        checkDefaultState: function () {
            var isRecordDataArray = _.isArray(this.recordData()),
                initialize,
                hasNotDefaultRecords = isRecordDataArray ? !!this.recordData().filter(function (data) {
                    return !data.initialize;
                }).length : false;

            if (!this.hasInitialPagesState[this.currentPage()] && isRecordDataArray && hasNotDefaultRecords) {
                this.hasInitialPagesState[this.currentPage()] = true;
                this.defaultPagesState[this.currentPage()] = utils.copy(this.getChildItems().filter(function (data) {
                    initialize = data.initialize;
                    delete data.initialize;

                    return initialize;
                }));

                this.setChangedForCurrentPage();
            } else if (this.hasInitialPagesState[this.currentPage()]) {
                this.setChangedForCurrentPage();
            }
        },

        arrayFilter: function (data) {
            var prop;

            /*eslint-disable no-loop-func*/
            data.forEach(function (elem) {
                for (prop in elem) {
                    if (_.isArray(elem[prop])) {
                        elem[prop] = _.filter(elem[prop], function (elemProp) {
                            return elemProp[this.deleteProperty] !== this.deleteValue;
                        }, this);

                        elem[prop].forEach(function (elemProp) {
                            if (_.isArray(elemProp)) {
                                elem[prop] = this.arrayFilter(elemProp);
                            }
                        }, this);
                    }
                }
            }, this);
            return data;
        },

        updateTrigger: function (val) {
            this.trigger('update', val);
        },

        hasChanged: function () {
            return this.changed();
        },

        renderColumnsHeader: function () {
            this.recordData().length ? this.columnsHeader(true) : this.columnsHeader(false);
        },

        initDefaultRecord: function () {
            if (this.defaultRecord && !this.recordData().length) {
                this.addChild();
            }

            return this;
        },

        createHeaderTemplate: function (prop) {
            var visible = prop.visible !== false,
                disabled = _.isUndefined(prop.disabled) ? this.disabled() : prop.disabled;

            return {
                visible: ko.observable(visible),
                disabled: ko.observable(disabled)
            };
        },

        initHeader: function () {
            var labels = [],
                data;

            if (!this.labels().length) {
                _.each(this.childTemplate.children, function (cell) {
                    data = this.createHeaderTemplate(cell.config);
                    cell.config.labelVisible = false;
                    _.extend(data, {
                        defaultLabelVisible: data.visible(),
                        label: cell.config.label,
                        name: cell.name,
                        required: !!cell.config.validation,
                        columnsHeaderClasses: cell.config.columnsHeaderClasses,
                        sortOrder: cell.config.sortOrder
                    });
                    labels.push(data);
                }, this);
                this.labels(_.sortBy(labels, 'sortOrder'));
            }
        },

        setMaxPosition: function (position, elem) {
            if (position || position === 0) {
                this.checkMaxPosition(position);
                this.sort(position, elem);
            } else {
                this.maxPosition += 1;
            }
        },

        sort: function (position, elem) {
            var that = this,
                sorted,
                updatedCollection;

            if (this.elems().filter(function (el) {
                    return el.position || el.position === 0;
                }).length !== this.getChildItems().length) {

                return false;
            }

            if (!elem.containers.length) {
                registry.get(elem.name, function () {
                    that.sort(position, elem);
                });

                return false;
            }

            sorted = this.elems().sort(function (propOne, propTwo) {
                return ~~propOne.position - ~~propTwo.position;
            });

            updatedCollection = this.updatePosition(sorted, position, elem.name);
            this.elems(updatedCollection);
        },

        checkSpinner: function (elems) {
            this.showSpinner(!(!this.recordData().length || elems && elems.length === this.getChildItems().length));
        },

        parsePagesData: function (data) {
            var pages;

            this.relatedData = this.deleteProperty ?
                _.filter(data, function (elem) {
                    return elem && elem[this.deleteProperty] !== this.deleteValue;
                }, this) : data;

            pages = Math.ceil(this.relatedData.length / this.pageSize) || 1;
            this.pages(pages);
        },

        reinitRecordData: function () {
            this.recordData(
                _.filter(this.recordData(), function (elem) {
                    return elem && elem[this.deleteProperty] !== this.deleteValue;
                }, this)
            );
        },

        getChildItems: function (data, page) {
            var dataRecord = data || this.relatedData,
                startIndex;

            this.startIndex = (~~this.currentPage() - 1) * this.pageSize;

            startIndex = page || this.startIndex;

            return dataRecord.slice(startIndex, this.startIndex + this.pageSize);
        },

        getRecordCount: function () {
            return _.filter(this.recordData(), function (record) {
                return record && record[this.deleteProperty] !== this.deleteValue;
            }, this).length;
        },

        getColumnsCount: function () {
            return this.labels().length + (this.dndConfig.enabled ? 1 : 0);
        },

        processingAddChild: function (ctx, index, prop) {
            this.bubble('addChild', false);

            if (this.relatedData.length && this.relatedData.length % this.pageSize === 0) {
                this.pages(this.pages() + 1);
                this.nextPage();
            } else if (~~this.currentPage() !== this.pages()) {
                this.currentPage(this.pages());
            }

            this.addChild(ctx, index, prop);
        },

        processingDeleteRecord: function (index, recordId) {
            this.deleteRecord(index, recordId);
        },

        changePage: function (page) {
            this.clear();

            if (page === 1 && !this.recordData().length) {
                return false;
            }

            if (~~page > this.pages()) {
                this.currentPage(this.pages());

                return false;
            } else if (~~page < 1) {
                this.currentPage(1);

                return false;
            }

            this.initChildren();

            return true;
        },

        isFirst: function () {
            return this.currentPage() === 1;
        },

        isLast: function () {
            return this.currentPage() === this.pages();
        },

        nextPage: function () {
            this.currentPage(this.currentPage() + 1);
        },

        previousPage: function () {
            this.currentPage(this.currentPage() - 1);
        },

        updatePosition: function (collection, position, elemName) {
            var curPos,
                parsePosition = ~~position,
                result = _.filter(collection, function (record) {
                    return ~~record.position === parsePosition;
                });

            if (result[1]) {
                curPos = parsePosition + 1;
                result[0].name === elemName ? result[1].position = curPos : result[0].position = curPos;
                this.updatePosition(collection, curPos);
            }

            return collection;
        },

        checkMaxPosition: function (position) {
            var max = 0,
                pos;

            this.elems.each(function (record) {
                pos = ~~record.position;
                pos > max ? max = pos : false;
            });

            max < position ? max = position : false;
            this.maxPosition = max;
        },

        removeMaxPosition: function () {
            this.maxPosition = 0;
            this.elems.each(function (record) {
                this.maxPosition < record.position ? this.maxPosition = ~~record.position : false;
            }, this);
        },

        onUpdateRecordTemplate: function (recordName) {
            if (recordName) {
                this.recordTemplate = recordName;
                this.reload();
            }
        },

        deleteRecord: function (index, recordId) {
            var recordInstance,
                lastRecord,
                recordsData,
                lastRecordIndex;

            if (this.deleteProperty) {
                recordsData = this.recordData();
                recordInstance = _.find(this.elems(), function (elem) {
                    return elem.index === index;
                });
                recordInstance.destroy();
                this.elems([]);
                this._updateCollection();
                this.removeMaxPosition();
                recordsData[recordInstance.index][this.deleteProperty] = this.deleteValue;
                this.recordData(recordsData);
                this.reinitRecordData();
                this.reload();
            } else {
                this.update = true;

                if (~~this.currentPage() === this.pages()) {
                    lastRecordIndex = this.startIndex + this.getChildItems().length - 1;
                    lastRecord =
                        _.findWhere(this.elems(), {
                            index: lastRecordIndex
                        }) ||
                        _.findWhere(this.elems(), {
                            index: lastRecordIndex.toString()
                        });

                    lastRecord.destroy();
                }

                this.removeMaxPosition();
                recordsData = this._getDataByProp(recordId);
                this._updateData(recordsData);
                this.update = false;
            }

            this._reducePages();
            this._sort();
        },

        _reducePages: function () {
            if (this.pages() < ~~this.currentPage()) {
                this.currentPage(this.pages());
            }
        },

        _getDataByProp: function (id, prop) {
            prop = prop || this.identificationProperty;

            return _.reject(this.getChildItems(), function (recordData) {
                return recordData[prop].toString() === id.toString();
            }, this);
        },

        _sort: function () {
            this.elems(this.elems().sort(function (propOne, propTwo) {
                return ~~propOne.position - ~~propTwo.position;
            }));
        },

        _updateData: function (data) {
            var elems = _.clone(this.elems()),
                path,
                dataArr;

            dataArr = this.recordData.splice(this.startIndex, this.recordData().length - this.startIndex);
            dataArr.splice(0, this.pageSize);
            elems = _.sortBy(this.elems(), function (elem) {
                return ~~elem.index;
            });

            data.concat(dataArr).forEach(function (rec, idx) {
                if (elems[idx]) {
                    elems[idx].recordId = rec[this.identificationProperty];
                }

                if (!rec.position) {
                    rec.position = this.maxPosition;
                    this.setMaxPosition();
                }

                path = this.dataScope + '.' + this.index + '.' + (this.startIndex + idx);
                this.source.set(path, rec);
            }, this);

            this.elems(elems);
        },

        reload: function () {
            this.clear();
            this.initChildren(false, true);
        },

        clear: function () {
            this.destroyChildren();

            return this;
        },

        reset: function () {
            var elems = this.elems();

            _.each(elems, function (elem) {
                if (_.isFunction(elem.reset)) {
                    elem.reset();
                }
            });
        },

        setClasses: function (data) {
            var additional;

            if (_.isString(data.additionalClasses)) {
                additional = data.additionalClasses.split(' ');
                data.additionalClasses = {};

                additional.forEach(function (name) {
                    data.additionalClasses[name] = true;
                });
            }

            if (!data.additionalClasses) {
                data.additionalClasses = {};
            }

            _.extend(data.additionalClasses, {
                '_fit': data.fit,
                '_required': data.required,
                '_error': data.error,
                '_empty': !this.elems().length,
                '_no-header': this.columnsHeaderAfterRender || this.collapsibleHeader
            });

            return data.additionalClasses;
        },

        initChildren: function () {
            this.showSpinner(true);
            this.getChildItems().forEach(function (data, index) {
                this.addChild(data, this.startIndex + index);
            }, this);

            return this;
        },

        setVisible: function (state) {
            this.elems.each(function (record) {
                record.setVisible(state);
            }, this);
        },

        setDisabled: function (state) {
            this.elems.each(function (record) {
                record.setDisabled(state);
            }, this);
        },

        setVisibilityColumn: function (index, state) {
            this.elems.each(function (record) {
                record.setVisibilityColumn(index, state);
            }, this);
        },

        setDisabledColumn: function (index, state) {
            this.elems.each(function (record) {
                record.setDisabledColumn(index, state);
            }, this);
        },

        addChild: function (data, index, prop) {
            var template = this.templates.record,
                child;

            index = index || _.isNumber(index) ? index : this.recordData().length;
            prop = prop || _.isNumber(prop) ? prop : index;

            _.extend(this.templates.record, {
                recordId: prop
            });

            child = utils.template(template, {
                collection: this,
                index: index
            });

            layout([child]);

            return this;
        },

        restoreToDefault: function () {
            this.recordData(utils.copy(this.default));
            this.reload();
        },

        setDifferedFromDefault: function () {
            var recordData = utils.copy(this.recordData());

            Array.isArray(recordData) && recordData.forEach(function (item) {
                delete item['record_id'];
            });

            this.isDifferedFromDefault(!_.isEqual(recordData, this.default));
        },

        setChangedForCurrentPage: function () {
            this.pagesChanged[this.currentPage()] =
                !compareArrays(this.defaultPagesState[this.currentPage()], this.arrayFilter(this.getChildItems()));
            this.changed(_.some(this.pagesChanged));
        }
    });
});
2

The best and simplest way to do this is through a UI modifier.

Set up your modifier in your etc/adminhtml/di.xml:

<virtualType name="Magento\Catalog\Ui\DataProvider\Product\Form\Modifier\Pool" 
             type="Magento\Ui\DataProvider\Modifier\Pool">
    <arguments>
        <argument name="modifiers" xsi:type="array">
            <item name="my-custom-modifier" xsi:type="array">
                <item name="class" xsi:type="string">YourVendor\YourModule\Ui\DataProvider\Product\Form\Modifier\UpdateCustomOptionPageSizeModifier</item>
                <item name="sortOrder" xsi:type="number">9999</item>
            </item>
        </argument>
    </arguments>
</virtualType>

You can then create your modifier like so:

<?php
/**
 *
 */
namespace YourVendor\YourModule\Ui\DataProvider\Product\Form\Modifier;

use Magento\Catalog\Ui\DataProvider\Product\Form\Modifier\AbstractModifier;
use Magento\Framework\Stdlib\ArrayManager;

class UpdateCustomOptionPageSizeModifier extends AbstractModifier
{    
    /**
     *
     */
    public function __construct(ArrayManager $arrayManager)
    {
        $this->arrayManager = $arrayManager;
    }

    /**
     * @param  array $meta
     * @return array
     */
    public function modifyMeta(array $meta)
    {
        $meta = $this->arrayManager->set(
            'custom_options/children/options/children/record/children/container_option/children/values/arguments/data/config/pageSize',
            $meta,
            1000 // This is the new PageSize value
        );
        
        return $meta;
    }
}

This answer is optimal as it doesn't require an extra JS file be downloaded and only changes it for this specific dynamic row, rather than all dynamic rows used in the Admin.

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Not the answer you're looking for? Browse other questions tagged or ask your own question.