jhipster / generator-jhipster

JHipster is a development platform to quickly generate, develop, & deploy modern web applications & microservice architectures.
https://www.jhipster.tech
Apache License 2.0
21.53k stars 4.02k forks source link

Paging And Sorting #797

Closed caosg closed 9 years ago

caosg commented 9 years ago

Please add paging capability and sorting capability .

mpages commented 9 years ago

what are you looking for paging and sorting client side on array? if so you should use ng-table

server side ? on sql db jpa repository has paging / sorting option, on mongo it native .. but you need to make your own rest service and param option + client side dev (could be heavy)

jdubois commented 9 years ago

@mpages is correct for both client and server-side options.

This goes a bit too far, regarding our current roadmap, as we aim to generate an application using "vanilla" AngularJS. So Adding ng-table is out of scope for the moment.

But this would be a great improvement to have a paging/sorting code, as most people will want this.

unknownboy commented 9 years ago

I can work on this (paging and sorting server side) as i already implemented this for another project using spring-boot and angularjs (client side paging using custom directive, without ng-table).

jdubois commented 9 years ago

What would be good is to have paging and sorting on server-side. This should be do-able as Spring Data provides methods to do just that. So it's a matter of plugging ng-table on Spring Data. I will also have a look at it.

MatthieuLebigre commented 9 years ago

I've implemented paging and sorting on server side, using Spring Data in a JHipster application. I could show you how I've done it, or create a pull request.

For the client side, I used ng-table. But maybe we could just implement the server side, and let the user implement the solution he wants on client-side ?

jdubois commented 9 years ago

@MatthieuLebigre this would be really cool to have an example with paging and sorting, from Spring Data JPA to ng-table. If you can share it, or even create a pull request: this would go in the "entity" sub-module, but maybe this should be an option? You could have a question asking if you want a "simple" or "advanced" page...

MatthieuLebigre commented 9 years ago

Do you think this should be an option ? I think it's something everyone should need at a point, and it doesn't add a lot of overhead, at least on server side. I'll work on this, but it will take a few time, since I didn't yet uprgrade to V2

jdubois commented 9 years ago

if it's simple, maybe it should be there by default ( @jmirc is that OK with you? ) In that case, we would also need to upgrade all the screens with this feature, but let's start simple with just the entity generator. Did you test it also with MongoDB?

MatthieuLebigre commented 9 years ago

Ok, anyway, I'll show you how I implement it. Unfortunately, I didn't test it with MongoDB, since I never used it ... :(

jdubois commented 9 years ago

OK, let's start with JPA anyway. And if you have time, you'll see that Spring Data MongoDB version works exactly the same, so your code will probably work easily.

MatthieuLebigre commented 9 years ago

:+1:

jmirc commented 9 years ago

I would like to see the code and evaluate the effort to integrate it. This is a good improvement because most of the advanced UI needs to handle this case. I agree with you @jdubois to only add it in the entity sub-generator and also the logs page so the page will load faster.

thiagonuic commented 9 years ago

I have also implemented this using spring data jpa and ng-table, it would be great to compare the solutions...

jmirc commented 9 years ago

Great! Could you share your code?

thiagonuic commented 9 years ago

Sure. I will separate in two posts, one for the server and one for the client.

Server:

On your REST method put:

public Page<Unit> getAll(@SortDefault(sort = {"name"}, direction = Sort.Direction.ASC) Pageable page)

The annotation is optional, but I like to have a default sorting.

Spring data JPA already recognizes the Pageable and returns the Page correctly, so querying is straight forward.

To protect the server from malicious people querying pages larger than what I want, I put the following code in the WebConfigurer:

@Bean
    @Override
    public PageableHandlerMethodArgumentResolver pageableResolver() {
        final PageableHandlerMethodArgumentResolver v_pageableHandlerMethodArgumentResolver = new PageableHandlerMethodArgumentResolver(sortResolver());
        v_pageableHandlerMethodArgumentResolver.setMaxPageSize(Constants.PAGE_SIZE);
        v_pageableHandlerMethodArgumentResolver.setFallbackPageable(new PageRequest(0, Constants.PAGE_SIZE));
        return v_pageableHandlerMethodArgumentResolver;
    }

My Constants.PAGE_SIZE right now is 30, and even if the person tries to override it this method should protect against it.

thiagonuic commented 9 years ago

Client side:

The HTML of ng-table usage is just like the documentation says:

<div class="table-responsive">
        <table class="table table-striped table-hover" ng-table="tableParams">
            <thead>
                <tr>
                    <th>{{'myTranslation' | translate}}</th>
                </tr>
            </thead>
            <tbody>
                <tr ng-repeat="row in $data">
                    <td>
                        {{row.field}}
                    </td>
                </tr>
            </tbody>
        </table>
    </div>

I prefer to specify the thead, but it is optional in simple cases, maybe for the generated code is not really useful.

The javascript part requires a little hack because the ng-table indexes the pages from 1 and java indexes from 0.

    $scope.tableParams = new ngTableParams({
            page: 1,            // show first page
            count: PAGE_SIZE,   // count per page
            sorting: {number: 'asc'}
        }, {
        total: 0,   // length of data
        counts: [], // hide page counts control
        getData: function($defer,  params)
        {
            var keys = Object.keys(params.$params.sorting);
            var object = {
                page: params.$params.page - 1,
                sort: keys[0] + "," + params.$params.sorting[keys[0]]
            };
            // Filtering present on the page
            var filters = Object.keys($scope.filter);
            for(var i=0; i < filters.length; i++)
            {
                object[filters[i]] = $scope.filter[filters[i]];
            }
            // Ajax call to update the table contents
            Domain.query(object, function(data)
            {
                if (data.content.length == 0 && data.number > 0)
                {
                    params.page(data.number);
                }
                else
                {
                    params.page(data.number + 1);
                    params.total(data.totalElements);
                    $defer.resolve(data.content);
                }
            });
        }
    });

As you can see the PAGE_SIZE constant is also present on my client side, I do not think letting the user specify page size is really useful, so I also hide the controls for it. The default sorting is there as well (sorting: {number: 'asc'}).

Most pages with tables also require filters so the user can find what he wants, to standarize this I get all the fields from $scope.filter and pass then along the query call. This way filtering is done on the server side.

So if you map an input to "filter.requester", all you need to do to get this information on the server is add an parameter on the REST method like this:

@RequestParam(value = "requester", required = false) String p_requester

And for date params:

@RequestParam(value = "startDate", required = false) @DateTimeFormat(iso = DateTimeFormat.ISO.DATE_TIME) Date p_startDate
Altaflux commented 9 years ago

If needed, my fork of Jhispter has implemented paging and sorting on the front end of angular without using ngTable, it is meant to be used against data-rest but it should be easily adapted to work with current controllers. You can check the code or use it if it is needed or is what you are looking for.

devedipoint commented 9 years ago

Also searching would be necessary

thiagonuic commented 9 years ago

Using my proposed solution all you need to do searching is map the field to "filter.yourField"

windhood commented 9 years ago

on mobile the more popular pagination style is the infinite scroll, so really we could provide two choices:ng-table and infinite scroll (which could be easily integrated with some angularjs plugin)

thiagonuic commented 9 years ago

@windhood could you provide some links or examples? Thanks.

windhood commented 9 years ago

yes, for an angularjs infinite scroll component: http://binarymuse.github.io/ngInfiniteScroll/ the demo link is here: http://binarymuse.github.io/ngInfiniteScroll/demo_async.html

I have developed angularjs mobile page and found mobile users seldom use pagination, they want the content to display as the content reaches the end of the screen/view (infinite scroll/pull up), just like another famous style - pull to refresh.

jdubois commented 9 years ago

I tried to implement it and I find it quite complex.

I am not sure it is a good fit for us, as we try to generate something simple, from which people can build on and add new functionality -> here we might go too far.

I am de-prioritizing this from the v2.0 release, and if you send me a good PR I will have a close look at it. Otherwise, I will close this ticket in a couple of weeks.

jdubois commented 9 years ago

OK, this is complex, and nobody is working on it for the moment : I agree we need to provide something better here, but it's currently out of scope