Jump to content

Issue with Grid Filters and pagination


Recommended Posts

Hello guys,

I am creating a module on the backoffice I wanted to display a page with the grid system but I cannot manage to make the filters and pagination work.

So the grid displays itself quite well, but no button using javascript seems to work, ie seems to be triggered. None of the actions within the GridActionCollection work when I click on it, when I type stuff on the filters input and click Search it just refreshes my grid page with no filter in it. The delete option does not work neither.

Weird stuff is when I edit in database directly the corresponding admin filter with a filter parameter or editing the limit value. Those filters are applied, meaning I can see the filter in the input, the grid is updated and the result count is the same as the limit. But the reset button does not do anything and the pagination is not triggered.

I don't understand what is going on because I literally did exactly the same as the documentation says but does not work. I tried to duplicate an example from prestashop admin also, the log page for instance. Same result.

It really seems to me that no js is linked to my grid template so nothing is triggered.

Moreover in the documentation, you describe a search action to be implemented. But nowhere is described how this route is called and when. So I really don't understand the process of Grid filters. And for the admin_common_reset_search, it uses a controller value and action. It does not say where should we configure or set this controller value so it can match...

Quote

hdclic.instaev.grid.definition.factory.galleries:
      class: 'Hdclic\Instaev\Grid\Definition\Factory\GalleryGridDefinitionFactory'
      parent: 'prestashop.core.grid.definition.factory.abstract_grid_definition'
      arguments:
            - "@=service('router').generate('admin_common_reset_search', {'controller': 'gallery', 'action': 'index'})"
            - "@=service('router').generate('instaev_admin_gallery_index')"
      public: true

class GalleryController extends FrameworkBundleAdminController
{
    public function indexAction(GalleryFilters $filters)
    {
        return $this->render(
            '@Modules/instaev/views/templates/admin/index.html.twig',
            [
                'grid' => $this->presentGrid($this->get('hdclic.instaev.grid.factory.galleries')->getGrid($filters)),
            ]
        );
    }

    public function searchAction(Request $request)
    {
        $definitionFactory = $this->get('hdclic.instaev.grid.definition.factory.galleries');
        $galleriesDefinition = $definitionFactory->getDefinition();

        $gridFilterFormFactory = $this->get('prestashop.core.grid.filter.form_factory');
        $searchParametersForm = $gridFilterFormFactory->create($galleriesDefinition);

        $searchParametersForm->handleRequest($request);
        $filters = [];

        if ($searchParametersForm->isSubmitted()) {
            $filters = $searchParametersForm->getData();
        }

        return $this->redirectToRoute('instaev_admin_gallery_index', ['filters' => $filters]);
    }

 

            ->add(
                (new Filter('actions', SearchAndResetType::class))
                    ->setTypeOptions([
                        'attr' => [
                            'data-url' => $this->resetActionUrl,
                            'data-redirect' => $this->redirectionUrl,
                        ],
                    ])
                    ->setAssociatedColumn('actions')
            )

 

please help 😢

 

Link to comment
Share on other sites

  • 6 months later...

Seems a bit of an old post, but I'm replying in case OP is still interested or somebody else stumbles upon this problem

I've ran into the same issue and solved as follows; beside the solution I'm providing a bit of an explanation and some stuff I've checked before resolving.

Check out this notes before reading if you want, as some thoughts to keep in mind for the future. Feel free to skip:

  1. PrestaShop version is not mentioned in your post
  2. I'm working with 1.7.7.3 development version
  3. I'm working with doc for 1.7
  4. This is a personal opinion and is not meant to disrespect the work of the mantainers: some sections of the doc seem incomplete and a work in progress (bottom page has the latest update which show many pages have been recently updated) and some require a bit of Symfony knowledge or may assume other knowledge (npm, webpack etc.) or knowledge from other sections that you may have not read because they are outside your area of interest (e.g. theme development) or just overlooked. All of this is more than fine by me, it's just an indication that you may want to look into other stuff beside the doc itself

As for the grid issue:

Quote

It really seems to me that no js is linked to my grid template so nothing is triggered.

This is indeed the problem; in this section of the doc (which isn't the module development but the core reference) is explained how to add JS features to your grid which, by default, has none. Such features are implemented inside the folder "admin-dev/themes/new-theme/js/components" and "admin-dev/themes/new-theme/js/app/utils".

However, as stated, the guide is meant for core and not module development so it will most likely fail or feel lacking of details.

Here's what you need to do:

  1. Create a JS file that initializes the required components described in the docs (SortingExtension, FiltersResetExtension and such, depending on which ones you want to use). This is how it's done in the doc:
     
    import Grid from '../../components/grid/grid';
    import SortingExtension from '../../components/grid/extension/sorting-extension';
    import FiltersResetExtension from '../../components/grid/extension/filters-reset-extension';
    import ReloadListActionExtension from '../../components/grid/extension/reload-list-extension';
    import ColumnTogglingExtension from '../../components/grid/extension/column-toggling-extension';
    import SubmitRowActionExtension from '../../components/grid/extension/action/row/submit-row-action-extension';
    import SubmitBulkExtension from '../../components/grid/extension/submit-bulk-action-extension';
    import BulkActionCheckboxExtension from '../../components/grid/extension/bulk-action-checkbox-extension';
    import ExportToSqlManagerExtension from '../../components/grid/extension/export-to-sql-manager-extension';
    
    const $ = window.$;
    
    $(() => {
      const taxGrid = new Grid('tax');
    
      taxGrid.addExtension(new ExportToSqlManagerExtension());
      taxGrid.addExtension(new ReloadListActionExtension());
      taxGrid.addExtension(new SortingExtension());
      taxGrid.addExtension(new FiltersResetExtension());
      taxGrid.addExtension(new ColumnTogglingExtension());
      taxGrid.addExtension(new SubmitRowActionExtension());
      taxGrid.addExtension(new SubmitBulkExtension());
      taxGrid.addExtension(new BulkActionCheckboxExtension());
    });

    But as you can see, the imports are using relative paths that are not correct for a module.
    You can probably change them to fit the "modules" directory but that may result in errors when working on a different environment (beside being a bad habit).

  2. In order to avoid using the relative paths, you need to implement webpack to use the appropriate ones. Luckily, inside this official tutorial there is already one that has everything you need. Download it and check out the "js" directory where you'll find:

    1. ".webpack" directory which contains the configuration scripts for webpack needed bundled to your final JS file

    2. "quotes" directory which contains the actual JS files that will be bundled. After renaming it to fit your grid (e.g. If you have a grid that's called 'ProductGrid', you can rename it to "product") you will place your extension loading file inside it

    3. package.json and webpack.config.js which are the npm and webpack config files

  3. Create the same directory structure under the root of your module (e.g. "modules/mymodule/js") including all subdirectories with "quotes" renamed as you wish. Inside your "views" directory ("modules/mymodule/views"*) create a "js" directory.

    *this is the place where you should place all the FE stuff, if you chose a different one you need to update the "output" definition for webpack inside "common.js" but you should use it as it is suggested.

  4. Copy the very same files in the same folders

  5. Now you need to:

    1. Update webpack entries in common.js:

      //original
      module.exports = {
        externals: {
          jquery: 'jQuery',
        },
        entry: {
          quotes: './quotes',
          quote_form: './quotes/form',
        },
      
      //modified
      module.exports = {
        externals: {
          jquery: 'jQuery',
        },
        entry: {
          mygrid: './mygrid',
        },

      where "mygrid" is the name you chose at point 2.2

    2. Update the resolution paths in the same file:

      //this block is at the top of the file
      const psRootDir = path.resolve(process.env.PWD, '../../../');
      const psJsDir = path.resolve(psRootDir, 'admin-dev/themes/new-theme/js');
      const psComponentsDir = path.resolve(psJsDir, 'components');
      //add an app dir which is needed by other components on which the extensions depend 
      const psAppDir = path.resolve(psJsDir, 'app');
      
      //this block is a bit below the exports we changed before
      resolve: {
          extensions: ['.js', '.vue', '.json'],
          alias: {
            //this is already present
            '@components': psComponentsDir,
             //this is what you add
            '@app': psAppDir,
          },
        },

       

    3. Rename the grid as explained in the doc to match the grid_id you have defined inside the GridDefinitionFactory in "index.js". You should also remove any extensions you are not using as not to load them needlessly

Now you can navigate from a terminal to your "js" folder and run "npm install" and once its finished "npm run dev" or "npm run build". If everything works fine, you'll see no errors (they are pretty clear and marked red) and the terminal will hang if you have used run dev (since inside the npm script definition inside "package.json" there is a watch flag that recompiles whenever the file changes); you can just interrupt it.

At this point, inside "views/js" you'll find a js file whose name starts with the grid name you chose at point 5.1 + bundle.js (e.g. "mygrid.bundle.js"). This is the final file that you need to include inside the twig template as per docs, like:

{% block javascripts %}
  {{ parent() }}
  <script src="{{ asset('../modules/mymodule/views/js/mygrid.bundle.js') }}"></script>
  <script src="{{ asset('themes/default/js/bundle/pagination.js') }}"></script>
{% endblock %}

Reload the page (check that you have disable caches from the BO performance section and if not do it and clean the cache) and try to clear filters.

As for the controller issue:

Quote

Moreover in the documentation, you describe a search action to be implemented. But nowhere is described how this route is called and when. So I really don't understand the process of Grid filters. And for the admin_common_reset_search, it uses a controller value and action. It does not say where should we configure or set this controller value so it can match...

I've not used the custom search action but the common one. Regardless, keep in mind that the grid filters are a form that POST onto itself which means you can define two different Symfony routes that answer two different HTTP verbs, POST and GET, like this:

//route for list action which is your index method inside the controller
my_route_summary_index:
  path: //path to your controller
  methods: [GET]
  defaults:
    _controller: //reference to the index method of your controller
    _legacy_controller: //same values you'd use for installTabs method (the one to get links in BO sidebar)
    _legacy_link: //same values you'd use for installTabs method (the one to get links in BO sidebar)

my_route_product_summary_search:
  path: //path to your controller, the same as above but below we put POST instead of GET
  methods: [POST]
  defaults:
    //this call the common search controller but you can use your own
    _controller: PrestaShopBundle:Admin\Common:searchGrid
    gridDefinitionFactoryServiceId: //your grid service
    redirectRoute: my_route_summary_index
    _legacy_controller: //same values as above
    _legacy_link: //same values as above followed by ":submitFilter<mygridname>" e.g. AdminMyModuleMyGrid:submitFiltermygrid

And you're done.

Edit: There is an ongoing debate among PrestaShop developers on whether or not to provide something to avoid the hassle of going through the steps required to enable the extension. See GitHub issues: https://github.com/PrestaShop/PrestaShop/pull/20591 and https://github.com/PrestaShop/PrestaShop/pull/21016

Edited by Gionatan
corrected second route dummy name (see edit history)
  • Like 2
Link to comment
Share on other sites

  • 3 months later...

Gionatan's solution is great, I can only add one small detail: I made a mistake by downloading the wrong release of presta and it had no package.json in the admin/themes/new-theme folder so the dependencies were incorrect and the npm build generated a ton of errors.

Link to comment
Share on other sites

  • 1 year later...

I've followed this documentation, but I get the following error when running npm run build:

ERROR in C:/websites/www8/admin-dev/themes/new-theme/js/components/modal/iframe-modal.ts
Module not found: Error: Can't resolve 'resize-observer-polyfill' in 'C:\websites\www8\admin-dev\themes\new-theme\js\components\modal'

ERROR in C:/websites/www8/admin-dev/themes/new-theme/js/components/grid/extension/position-extension.ts
Module not found: Error: Can't resolve 'tablednd/dist/jquery.tablednd.min' in 'C:\websites\www8\admin-dev\themes\new-theme\js\components\grid\extension'

ERROR in chunk grid [entry]
grid.bundle.js
C:\websites\www8\modules\lscartoffers\views\js\grid\index.js 17f5a5c3b8203601754cb0a169196040
Unexpected token (222:38)
|         if (iframeContainer) {
|             this.cleanResizeObserver();
|             this.resizeObserver = new !(function webpackMissingModule() { var e = new Error("Cannot find module 'resize-observer-polyfill'"); e.code = 'MODULE_NOT_FOUND'; throw e; }())(function () {
|                 _this.autoResize();
|             });

ERROR in C:\websites\www8\admin-dev\themes\new-theme\tsconfig.json
[tsl] ERROR
      TS2688: Cannot find type definition file for 'vue'.
  The file is in the program because:
    Entry point for implicit type library 'vue'

ERROR in C:\websites\www8\admin-dev\themes\new-theme\js\components\auto-complete-search.ts
[tsl] ERROR in C:\websites\www8\admin-dev\themes\new-theme\js\components\auto-complete-search.ts(37,49)
      TS2503: Cannot find namespace 'Twitter'.

as well as other similar errors.  Quite stuck on this, seems like quit an uphill struggle to get a simple grid to display and work in a prestashop 8 module.

Edited by mzfp (see edit history)
Link to comment
Share on other sites

  • 2 months later...

Hey guys, I had posted an update following "mzfp" because at the time I wrote the answer we were in version 1.7 but for some reason it wasn't published 😕 . Luckily, things have gotten way more easier in PrestaShop's latest version. Idk if this comment will go through but if it does feel free to dm me and we can take a look together (sorry, I'm not going to post again the answer that wasn't published).

Link to comment
Share on other sites

Create an account or sign in to comment

You need to be a member in order to leave a comment

Create an account

Sign up for a new account in our community. It's easy!

Register a new account

Sign in

Already have an account? Sign in here.

Sign In Now
×
×
  • Create New...