Batching in Volto

Good afternoon, Plone community.

I am planning on setting up batching for at least 25 items on a Volto site. Currently, I am using a form of data tables from datatables.net to display the table data in a nice searchable view. However, when i go to search for more than 25 items, i find that the number of items displaying in the counter is inaccurate and showing 0 out of 0 items when in fact there are 25 items. How would i go about doing batching in Volto?

I thank you kindly.

Sincerely,

rbrown12

Hi! I think we'd have to see some code, for the context, otherwise it's hard to tell what the issue could be.

Here is some of the code below which displays the datatables in the view:

import React, { useEffect } from 'react';
import 'datatables.net-se';
import moment from 'moment';
import { Container, Table, Modal } from 'semantic-ui-react';
import 'datatables.net-buttons-se';
import 'datatables.net-colreorder-se';
import 'datatables.net-select-se';
import 'jszip';
import pdfMake from 'pdfmake/build/pdfmake';
import pdfFonts from 'pdfmake/build/vfs_fonts';
import 'datatables.net-buttons/js/buttons.colVis.js';
import 'datatables.net-buttons/js/buttons.html5.js';
import 'datatables.net-buttons/js/buttons.print.js';
import '../styles.css';
import $ from 'jquery';
import PDFViews from '../../PDFViews/PDFViews';
import { Link } from 'react-router-dom';
import ContentStatusHistory from '../../ContentStatusHistory/ContentStatusHistory';
import History from '../../History/History';
import { useSelector, useDispatch } from 'react-redux';
import { searchContent } from '../../../actions/search/search';
pdfMake.vfs = pdfFonts.pdfMake.vfs;

const DataTablesBase = (content) => {
  const results = useSelector(
    (state) => state.search.subrequests.content?.items,
  );
  const dispatch = useDispatch();
  useEffect(() => {
    dispatch(
      searchContent(
        '/',
        {
          meta_type: 'Dexterity Item',
          fullobjects: true,
        },
        'content',
      ),
    );
  }, [dispatch]);

  // DataTables function
  useEffect(() => {
    $(document).ready(() => {
      $('#table').DataTable({
        dom: 'Bflrtip',
        select: true,
        colReorder: true,
        lengthMenu: [25, 50, 75, 100],
        lengthChange: false,
        deferRender: true,
        buttons: [
          'colvis',
          'copy',
          'csv',
          'excel',
          'pdf',
          'print',
          'pageLength',
        ],
        bDestroy: true,
      });
    });
  }, []);

  // Render component returned
  return (
    <Container className="view-wrapper">
      <header>
        {content.title && (
          <h1 className="documentFirstHeading">{content.title}</h1>
        )}
        {content.description && (
          <p className="documentDescription">{content.description}</p>
        )}
      </header>
      <Table celled striped sortable id="table" className="listing">
        <Table.Header>
          <Table.Row>
            <Table.HeaderCell>#</Table.HeaderCell>
            <Table.HeaderCell>Incoming Seek</Table.HeaderCell>
            <Table.HeaderCell>Created</Table.HeaderCell>
            <Table.HeaderCell>empID</Table.HeaderCell>
            <Table.HeaderCell>First Name</Table.HeaderCell>
            <Table.HeaderCell>Last Name</Table.HeaderCell>
            <Table.HeaderCell>Documents</Table.HeaderCell>
            <Table.HeaderCell>State</Table.HeaderCell>
            <Table.HeaderCell className="sorting_disabled">
              Action
            </Table.HeaderCell>
          </Table.Row>
        </Table.Header>
        <Table.Body>
          {results &&
            results.map((item, i) => (
              <Table.Row key={item.id}>
                <Table.Cell>
                  <div>{i + 1}</div>
                </Table.Cell>
                <Table.Cell>
                  {(item.incoming_seek && item.incoming_seek.title) ||
                    (item.incoming_seek && item.incoming_seek.token)}
                </Table.Cell>
                <Table.Cell>
                  <div>{moment(item.created).format('ll')}</div>
                </Table.Cell>
                <Table.Cell>
                  <div>{item.employeeID}</div>
                </Table.Cell>
                <Table.Cell>
                  <div>{item.first_name}</div>
                </Table.Cell>
                <Table.Cell>
                  <div>{item.last_name}</div>
                </Table.Cell>
                <Table.Cell>
                  <div>
                    <ol>
                      {item.attachment_type && (
                        <li>
                          <Modal
                            trigger={<Link>{item.attachment_type.title}</Link>}
                            scrolling
                            closeIcon
                          >
                            <Modal.Header>
                              {item.attachment_type.title}
                            </Modal.Header>
                            <Modal.Content>
                              <PDFViews file={item.attachment_file.download} />
                            </Modal.Content>
                          </Modal>
                        </li>
                      )}
                      {item.attachment_type1 && (
                        <li>
                          <Modal
                            trigger={<Link>{item.attachment_type1.title}</Link>}
                            scrolling
                            closeIcon
                          >
                            <Modal.Header>
                              {item.attachment_type1.title}
                            </Modal.Header>
                            <Modal.Content>
                              <PDFViews file={item.attachment_file1.download} />
                            </Modal.Content>
                          </Modal>
                        </li>
                      )}
                      {item.attachment_type2 && (
                        <li>
                          <Modal
                            trigger={<Link>{item.attachment_type2.title}</Link>}
                            scrolling
                            closeIcon
                          >
                            <Modal.Header>
                              {item.attachment_type2.title}
                            </Modal.Header>
                            <Modal.Content>
                              <PDFViews file={item.attachment_file2.download} />
                            </Modal.Content>
                          </Modal>
                        </li>
                      )}
                      {item.attachment_type3 && (
                        <li>
                          <Modal
                            trigger={<Link>{item.attachment_type3.title}</Link>}
                            scrolling
                            closeIcon
                          >
                            <Modal.Header>
                              {item.attachment_type3.title}
                            </Modal.Header>
                            <Modal.Content>
                              <PDFViews file={item.attachment_file3.download} />
                            </Modal.Content>
                          </Modal>
                        </li>
                      )}
                      {item.attachment_type4 && (
                        <li>
                          <Modal
                            trigger={<Link>{item.attachment_type4.title}</Link>}
                            scrolling
                            closeIcon
                          >
                            <Modal.Header>
                              {item.attachment_type4.title}
                            </Modal.Header>
                            <Modal.Content>
                              <PDFViews file={item.attachment_file4.download} />
                            </Modal.Content>
                          </Modal>
                        </li>
                      )}
                    </ol>
                  </div>
                </Table.Cell>
                <Table.Cell>
                  <div>{item.review_state}</div>
                </Table.Cell>
                <Table.Cell>
                  <div>
                    <Table>
                      <Table.Body>
                        <Table.Row>
                          <Table.Cell>
                            <Modal
                              closeIcon
                              trigger={<Link>View</Link>}
                              scrolling
                            >.....</Modal>
                          </Table.Cell>
                          <Table.Cell>
                            <Modal
                              closeIcon
                              trigger={<Link>History</Link>}
                              scrolling
                            >
                              <Modal.Header>
                                <h1 className="documentFirstHeading">
                                  {item.last_name}, {item.first_name} -{' '}
                                  {item.employeeID}
                                </h1>
                                <p>
                                  <em>
                                    <span> last modified </span>
                                    <span>
                                      {' '}
                                      {moment(item.modified).fromNow('ll')}
                                    </span>
                                    <span> ago </span>{' '}
                                  </em>
                                </p>
                              </Modal.Header>
                              <Modal.Content>
                                <div>
                                  <History
                                    location={{
                                      pathname: item.url + '/history',
                                    }}
                                  />
                                </div>
                              </Modal.Content>

                              <br />
                            </Modal>
                          </Table.Cell>
                        </Table.Row>
                      </Table.Body>
                    </Table>
                  </div>
                </Table.Cell>
              </Table.Row>
            ))}
        </Table.Body>
      </Table>
    </Container>
  );
};

export default DataTablesBase;

It seems a bit odd using jquery+datatables mixed on top of React, but kudos for making it work! Personally I prefer native React libraries, probably something like https://react-table.tanstack.com/

In any case, I think the problem is that there's no integration between the datatable that you're using and any form of pagination. You might be able to overcome this by setting a very high b_size parameter in the search action call, but it seem that you're just asking jquery and React to have a fight over that table's DOM. I'd go with the "native react" solution and integrate with the plone.restpai batching, see Batching — plone.restapi 1.0a1 documentation