简体   繁体   中英

How to manage pagination in multiple tables in grails?

I have two tables(sections) in my gsp page and I need to implement pagination on both of them. The number of records in each page of a table / section is different(eg. first table should show 10 records per page and second table / section should display 7 records per page). I implemented it using tag. When I did so, I got lots of problems as mentioned below.

  1. Initially it shows number of records as given for each tables. But when I click Next button in one page, whole page gets refreshed and both tables goes to page 2 and so on. When all pages are done in one page and click next in the other table, it shows shows blank page for the table with less number of pages and next table shows new page. Eg: If table 1 has 5 pages and table 2 has 9 pages, when we go to page 6 of second table, first table is shown BLANK.

  2. Sometimes, when I click next button, the number of records displayed are not consistent. Eg. Sometimes it shows 10 records per page, next time 5 records like this. This happens for both the tables.

  3. This is a normal call to the controller method and not the ajax call. Could you please give me sample of ajax call?

Could any one help me with these issues?I would really appreciate if anyone could give me the code for the controller and gsp page for multiple pagination implementation.

Thanks in advance.

First lets assume that you have the following classes.

LANGUAGE

class Language {

    String name

    static constraints = {}
}

PERSON

class Person {
 String name

 static constraints = {}
}

First we need to define whether we are going to use AJAX or not. Why is that? Because when using static pages you will need to pass the params of both paginates to and from a controller action. When using AJAX it would be more useful to have two different actions so you won´t have to pass all params to the action.

For this example we are going to go through the simpler AJAX path.

First we need to identify what data we need for a paginate tag.

  • Total: This one required for the tag
  • action: Since we are going to have 2 different actions, then we need to specify which action will be used by the tag
  • Controller: In case you generate the lists in diferent controllers
  • offset: The offset of the page
  • max: The max number of elements in the page

Now lets assume that we are going to put both actions in a single controller named main.

class MainController {

    /**The action that will load the list of people*/
    def personaList(){

        params.max = params?.max ?: 10
        params.offset = params?.offset ?: 0
        def personList = Person.list(params)

        render template: 'personaList',
        model: [
            personList : personList,
            personTotal: Person.count,
            max: params.max,
            offset: params.offset
        ]
    }


    /**The action that will load the list of languages*/
    def languageList(){

        params.max = params?.max ?: 10
        params.offset = params?.offset ?: 0
        def languageList = Language.list(params)

        render template: 'languageList',
                model: [
                        languageList : languageList,
                        languageTotal: Language.count,
                        max: params.max,
                        offset: params.offset
                ]
    }
}

Since we are going to work with ajax then we should use templates to render. We are going to create a template to render for each action

Language template _languateList

<table>
    <thead>
    <tr><th>Name</th></tr>
    </thead>
    <tbody>
    <g:each in="${languageList}" var="language">
        <tr>
            <td>${language.name}</td>
        </tr>
    </g:each>
    </tbody>
</table>

<div class="paginate">
    <g:paginate total="${languageTotal ?: fraglist.Language.count}" 
               controller="main" action="languageList"
               max="${max ?: 10}" offset="${offset ?: 0}" />
</div>

Persona Template _personList

<table>
    <thead>
        <tr><th>Name</th></tr>
    </thead>
    <tbody>
        <g:each in="${personList}" var="person">
            <tr>
                <td>${person.name}</td>
            </tr>
        </g:each>
    </tbody>
</table>

<div class="paginate">
    <g:paginate total="${personTotal ?: fraglist.Person.count}" controller="main" action="personaList"
                max="${max ?: 10}" offset="${offset ?: 0}" />
</div>

And finally in our view we need to add a little jquery. The jquery function adds the click event handler to all the links that are created by the paginate tag. For the default case for each table we use the include tag. We also define two elements where each list will load its new content.

<!DOCTYPE html>
<html>
    <head>
        <meta name="layout" content="main"/>
        <title>Welcome to Grails</title>
    </head>
    <body>

        <div id="table-person" class="table-container">
            <g:include controller="main" action="personaList" />
        </div>

        <div id="table-language" class="table-container">
            <g:include controller="main" action="languageList" />
        </div>


        <script>
            (function($){
                $(document).ready(function(){
                    $(".table-container").on('click', '.paginate a', function(event){
                        event.preventDefault();
                        var linkItem  =  $(this);
                        var target = linkItem.closest('div.table-container');
                        $.get(linkItem.prop('href'))
                                .done(function(data){
                                    target.html(data);
                                }).fail(function(){
                                    alert("There was an error loading the data");
                                });
                    });
                });
            })(jQuery)
        </script>
    </body>
</html>

This is the simplest example that I could come up with where you can have two ajax-paginated lists in the same view.

I don't know if there's an easier solution, but for these cases I have copied the source code of the paginate tag and created a new secondTablePaginate tag. Change the parameters of the new tag to secondTableTotal and secondTableOffset, both in the GSP and in the source code and you should be all set.

I had the same problem, in my gsp view I have two tables and two pagers, but when I paginated in a table I used the other table, I was researching and I found an example code that helped me a lot and solved my problem, what they do is to save the maximum value and the offset in session and use it in the g: paginate directive. I leave the link to the example and the sample code:

LINK: https://code-examples.net/es/q/3de823

controller

class PageController {

  def index = {
    if (params.paginate == 'Foo') {
      def fooPagination = [max: params.max, offset: params.offset]
      session.fooPagination = fooPagination
    } else if (params.paginate == 'Bar') {
      def barPagination = [max: params.max, offset: params.offset]
      session.barPagination = barPagination
    }
    def barList = Bar.list(session.barPagination ?: [max: 10, offset: 0])
    def fooList = Foo.list(session.fooPagination ?: [max: 10, offset: 0])
    //This is to stop the paginate using params.offset/max to calculate current step and use the offset/max attributes instead    
    params.offset = null
    params.max = null
    [fooList: fooList, totalFoos: Foo.count(), totalBars: Bar.count(), barList: barList]
  }
}

index.gsp

<html>
<head>
  <title>Multi Pagination Example</title>

  <meta name="layout" content="main"/>
  <style type="text/css" media="screen">

  h2 {
    margin-top: 15px;
    margin-bottom: 15px;
    font-size: 1.2em;
  }
  </style>

</head>
<body>
<table>
  <tr>
    <td>
      <h2>Foo</h2>
      <table>
        <tr>
          <th>Name</th>
        </tr>
        <g:each in="${fooList}">
          <tr><td>${it.name}</td></tr>
        </g:each>
        <tr>
          <td class="paginateButtons">
            <g:paginate total="${totalFoos}" max="10" offset="${session.fooPagination?.offset}" params="${[paginate:'Foo']}"/></td>
        </tr>
      </table>
    </td>
    <td>
      <h2>Bar</h2>
      <table>
        <tr>
          <th>Name</th>
        </tr>
        <g:each in="${barList}">
          <tr><td>${it.name}</td></tr>
        </g:each>
        <tr>
          <td class="paginateButtons">
            <g:paginate total="${totalBars}" max="10" offset="${session.barPagination?.offset}" params="${[paginate:'Bar']}"/></td>
        </tr>
      </table>
    </td>
  </tr>
</table>

</body>
</html>

I hope it serves you like me

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM