How to implement a pagination system for Read-Only fields


Table of contents




Limitations

  • The pagination system can only be implemented on Read-Only (multivalue) fields

  • The pagination system can only works on the Issue View so must implemented in the Display view configuration.

  • The pagination sytem requires Javascript to be authorized at field level, which is not recommended for security reasons. Customers should be warned of this risk.

Step 1 - Authorize Javascript

In order to run Javascript in a Connect field, you need to do the following:

  • Go to Settings (gear) => System => General Configuration

  • Click “Edit Settings”

  • Enable HTML in field, as follows:

Step 2 - Disable Inline Edit

With a pagination system, you need to click on buttons to move from one page to another. These buttons are part of the Connect field, so when you click on them, inline editing is triggered. You need to disable it as follows:

  • Go to Settings (gear) => System => Announcement Banner

  • Add the following script:

    <script type="text/javascript"> 
    AJS.$(document).ready(function() {
    setInterval(function() {
      AJS.$('#customfield_XXXXX-val').removeAttr('class');
      AJS.$('#customfield_XXXXX-val').children('.icon').remove();
      AJS.$('#customfield_XXXXX-val').removeAttr( "title" )
    AJS.$('#customfield_XXXXX-val').removeClass("editable-field");
    }, 200);
     });
    </script>

    (info) Replace customfield_XXXXX with the Connect field ID

Step 3 - Configure the pagination system in the field configuration

(info) The pagination system can only work on the Issue view, so it must be implemented in the Display view configuration.

Let’s take the following Connect field query as an example:

  • Database: Jira database (SQL)

  • Query:

    SELECT ID, issuenum,project,reporter,summary
    FROM jiraissue
  • Editor component: Read-only (multi-value)

  • Template: Custom HTML

    • Header:
      <style>
      .table_wrapper{
          display: block;
          overflow-x: auto;
          white-space: nowrap;  
      }
      </style>
      <div class="table_wrapper">
      <table class="aui" >
        <thread>
          <tr>
            <th>Id</th>
            <th>Issue Num</th>
            <th>Project</th>
            <th>Reporter</th>
            <th>Summary</th>
          </tr>
        </thread>
      <tbody>
    • Body:
      <tr>
        <th>{0}</th>
        <th>{1}</th>
        <th>{2}</th>
        <th>{3}</th>
        <th>{4}</th>
      </tr>
    • Footer:
      </tbody>
      </table>
      </div>


This is how to configure a pagination system in the Display view tab:

  • Template: Custom HTML:

    • Header:
      <style>
          #customfield_XXXXX-val .overlay-icon.aui-icon.aui-icon-small.aui-iconfont-edit {
              display: none;
          }   
      
          #pagination-container {
              padding-top: 2px;
              display: flex;
      
              align-items: center; 
              flex-wrap: wrap; 
          }
      
          .pagination-button {
              cursor: pointer;
              flex: 0 0 auto; 
              min-width: 5%;
              margin: 5px; 
          }
          
          .table_wrapper{
            display: block;
            overflow-x: auto;
            white-space: nowrap;  
          }
      </style>
      
      <div class="table_wrapper">
          <table id="result-table" class="aui">
              <thead>
                  <tr>
                    <th>Id</th>
                    <th>Issue Num</th>
                    <th>Project</th>
                    <th>Reporter</th>
                    <th>Summary</th>
                  </tr>
              </thead>
              <tbody id="list-container">
              </tbody>
          </table>
      </div>
      <div id="pagination-container"></div>
      <script>
          var items = [];</script>
      (info) Replace customfield_XXXXX with the Connect field ID

    • Body:
      <script>items.push([`{0}`, `{1}`, `{2}`, `{3}`, `{4}`]);</script>
    • Footer:
      <script>
          const itemsPerPage = 5;
          let currentPage = 1;
      
          const listContainer = document.getElementById('list-container');
          const paginationContainer = document.getElementById('pagination-container');
      
          function updateList() {
              const startIndex = (currentPage - 1) * itemsPerPage;
              const endIndex = startIndex + itemsPerPage;
              const itemsToShow = items.slice(startIndex, endIndex);
      
              listContainer.innerHTML = '';
      
              itemsToShow.forEach(itemSet => {
                  const row = document.createElement('tr');
                  itemSet.forEach(item => {
                      const cell = document.createElement('td');
                      cell.textContent = item;
                      row.appendChild(cell);
                  });
                  listContainer.appendChild(row);
              });
          }
      
      
          function updatePaginationButtons(totalPages) {
              const maxButtonsToShow = 10;
              const maxButtonsEitherSide = Math.floor((maxButtonsToShow - 1) / 2); 
              let startPage = Math.max(1, currentPage - maxButtonsEitherSide);
              let endPage = Math.min(totalPages, startPage + maxButtonsToShow - 1);
              
              if (endPage - startPage < maxButtonsToShow - 1) {
                  startPage = Math.max(1, endPage - maxButtonsToShow + 1);
              }
      
              for (let i = startPage; i <= endPage; i++) {
                  const button = document.createElement('button');
                  button.textContent = i;
                  button.classList.add('pagination-button');
                  button.classList.add('aui-button');
                  if (i === currentPage) {
                      button.disabled = true;
                  }
                  button.addEventListener('click', () => {
                      currentPage = i;
                      updateList();
                      updatePagination();
                  });
                  paginationContainer.appendChild(button);
              }
          }
      
          function updatePagination() {
              paginationContainer.innerHTML = '';
      
              const totalPages = Math.ceil(items.length / itemsPerPage);
      
              if (totalPages <= 1) {
                  return;
              }
      
              const prevButton = document.createElement('button');
              prevButton.textContent = '<';
              prevButton.classList.add('pagination-button');
              prevButton.classList.add('aui-button');
              prevButton.addEventListener('click', () => {
                  if (currentPage > 1) {
                      currentPage--;
                      updateList();
                      updatePagination();
                  }
              });
              paginationContainer.appendChild(prevButton);
      
              updatePaginationButtons(totalPages);
      
              const nextButton = document.createElement('button');
              nextButton.textContent = '>';
              nextButton.classList.add('pagination-button');
              nextButton.classList.add('aui-button');
              nextButton.addEventListener('click', () => {
                  if (currentPage < totalPages) {
                      currentPage++;
                      updateList();
                      updatePagination();
                  }
              });
              paginationContainer.appendChild(nextButton);
          }
      
          // Initial update
          updateList();
          updatePagination();
      </script>