user6680
user6680

Reputation: 139

Server-side pagination using ngx-pagination

I got the ngx-pagination module working with all the listings in the GET, but I want the pagination to work server-side too, but I'm unsure how to implement it further than what I have. I'm looking at the documentation for ngx-pagination, but I'm a little bit confused. Here's what I have.

html code

<body [ngClass]="[(this.isOpen && this.mobile) || (this.isOpen && this.tablet) ? 'hideContent' : 'showContent']">
    <div class="loading">
        <!-- <mat-spinner class="loader" *ngIf="isLoading"></mat-spinner> -->

        <ngx-spinner id="loadingIcon" *ngIf="isLoading" type="cog" size="large" color="#3071a9">


            <p class="loadingTitle">Loading...</p>
        </ngx-spinner>

    </div>

    <div class="spacing"></div>
    <div class="container">
        <div class="row no-gutters"
            *ngIf="!this.isOpen && this.mobile || this.isOpen && !this.mobile || !this.isOpen && !this.mobile">
            <div class="class col-md-7"></div>

        </div>

        <!-- /|slice:0:show -->
        <!--; let i = index-->
        <div class="row"
            *ngFor="let auction of posts | paginate: { itemsPerPage: 10, currentPage: p, totalItems: this.posts.count }">
            <div class="col-md-12 col-centered">

                <div class="listingCard" [@simpleFadeAnimation]="'in'">

                    <div class=container>

                        <div class="row">
                            <div class="col-md-3">

                            </div>
                            <div class="col-md-6">
                                <div id="title">{{auction.title}}</div>
                            </div>

                        </div>

                    </div>



                </div>
            </div>

        </div>

    </div>

    <pagination-controls (pageChange)="p = $event"></pagination-controls>

</body>

</html>

<!DOCTYPE html>
<html>

<head>
</head>

<body [ngClass]="[(this.isOpen && this.mobile) || (this.isOpen && this.tablet) ? 'hideContent' : 'showContent']">
    <div class="loading">
        <!-- <mat-spinner class="loader" *ngIf="isLoading"></mat-spinner> -->
        <ngx-spinner id="loadingIcon" *ngIf="isLoading" type="cog" size="large" color="#3071a9">

            <p class="loadingTitle">Loading...</p>
        </ngx-spinner>
    </div>
    <div class="spacing"></div>
    <div class="container">
        <div class="row no-gutters"
            *ngIf="!this.isOpen && this.mobile || this.isOpen && !this.mobile || !this.isOpen && !this.mobile">
            <div class="class col-md-7"></div>
        </div>
        <!-- /|slice:0:show -->
        <!--; let i = index-->
        <div class="row"
            *ngFor="let auction of posts | paginate: { itemsPerPage: 10, currentPage: p, totalItems: this.posts.count }">
            <div class="col-md-12 col-centered">
                <div class="listingCard" [@simpleFadeAnimation]="'in'">
                    <div class=container>
                        <div class="row">
                            <div class="col-md-3">
                            </div>
                            <div class="col-md-6">
                                <div id="title">{{listing.title}}</div>
                            </div>
                        </div>
                    </div>
                    =
                </div>
            </div>
        </div>
    </div>
    <pagination-controls (pageChange)="p = $event"></pagination-controls>
</body>

.ts File component

 p: number = 1;

ngOnInit(){
    this.submitListingService.getListings(this.postsPerPage, this.currentPage);
    this.listingService
      .getPostUpdateListener()
      .pipe(takeUntil(this.destroy))
      .subscribe((postData: { listing: Listing[]; postCount: number }) => {
        this.isLoading = false;
        this.totalPosts = postData.postCount;
        this.posts = postData.listing;
        this.filteredPosts = postData.listing;
      });
}

Angular service

getListings(postsPerPage: number, currentPage: number) {
    let listings = "Get Listings";
    const params = new HttpParams().set("listings", listings);
    const queryParams = `?pagesize=${postsPerPage}&page=${currentPage}`;
    this.http
      .get<{ message: string; posts: any; maxPosts: number }>(
        "http://localhost:3000/api/listings" + queryParams,
        { params }
      )
      .pipe(
        map(postData => {
          return {
            posts: postData.posts.map(post => {
              return {
               title: post.title,                   
                id: post._id
              };
            }),
            maxPosts: postData.maxPosts
          };
        })
      )
      .pipe(takeUntil(this.destroy))
      .subscribe(transformedPostData => {
        this.posts = transformedPostData.posts;
        this.postsUpdated.next({
          listing: [...this.posts],
          postCount: transformedPostData.maxPosts
        });
      });
  }

-> Server Code
app.js

app.get("/api/listings", (req, res, next) => {
  Post.find({ auctionEndDateTime: { $gte: Date.now() } })
      .populate("creator", "username")
      .then(documents => {
        req.params.Id = mongoose.Types.ObjectId(req.params.Id);
        res.status(200).json({
          message: "Auction listings retrieved successfully!",
          posts: documents
        });
      });
});

Upvotes: 0

Views: 1233

Answers (3)

C.Gochev
C.Gochev

Reputation: 1922

Here is another way to do this. This might be a better fit for your case.

  Post.find({ auctionEndDateTime: { $gte: Date.now() } })
      .populate("creator", "username")
      .then(documents => {
          req.params.Id = mongoose.Types.ObjectId(req.params.Id);

          let per_page = req.query.pagesize;
          let page = req.query.page || 1;
          let offset = (page - 1) * per_page;
        res.status(200).json({
          message: "Auction listings retrieved successfully!",
          posts: documents.slice(offset).slice(0,
                per_page)

        });
      });

and here is one more approach using slice

  var skip = req.query.pagesize * (req.query.page - 1)

        Post.where('auctionEndDateTime').gte(Date.now()).slice([skip, req.query.pagesize])
                      .populate("creator", "username")
                      .then(documents => {

              res.status(200).json({
                 message: "Auction listings retrieved successfully!",
                 posts: documents
              });
          })

Upvotes: 1

Pushprajsinh Chudasama
Pushprajsinh Chudasama

Reputation: 7949

Your Service File ,

getListings(postsPerPage: number, currentPage: number) {
    // let listings = "Get Listings";
    // const params = new HttpParams().set("listings", listings);
    // const queryParams = `?pagesize=${postsPerPage}&page=${currentPage}`;
    const queryParams = postsPerPage+"/"+currentPage; //change this .
    this.http
    .get<{ message: string; posts: any; maxPosts: number }>(
        "http://localhost:3000/api/listings/" + queryParams
        )
    .pipe(
        map(postData => {
            return {
                posts: postData.posts.map(post => {
                    return {
                        title: post.title,                   
                        id: post._id
                    };
                }),
                maxPosts: postData.maxPosts
            };
        })
        )
    .pipe(takeUntil(this.destroy))
    .subscribe(transformedPostData => {
        this.posts = transformedPostData.posts;
        this.postsUpdated.next({
            listing: [...this.posts],
            postCount: transformedPostData.maxPosts
        });
    });
}

As you are sending parameters so you need to change the URL of API as below i mentioned in server code ,

Your Server code will be as follow ,

app.get("/api/listings/:postPerPage/:currentPage", (req, res, next) => {
    let postPerPage = req.params.postPerPage;
    let currentPage = req.params.currentPage;
    Post.find({ auctionEndDateTime: { $gte: Date.now() } })
    .populate("creator username")
    .skip(postPerPage * currentPage)
    .limit(postPerPage)
    .then(documents => {
        req.params.Id = mongoose.Types.ObjectId(req.params.Id);
        res.status(200).json({
            message: "Auction listings retrieved successfully!",
            posts: documents
        });
    });
});

From the above code you will get the post equals to postPerPage .

Hope this is what you looking for . Thank you

Upvotes: 0

Santgurlal Singh
Santgurlal Singh

Reputation: 167

You will need two values on server side one is page i.e. which page number to show and second is limit i.e. how many results to show on the page. Then just use:

.skip(limit * (page - 1)).limit(limit)

First operator will skip the unwanted results for eg: if page is 2 and limit is 20 then in first operation the first 20 results will be skipped then in second operation we will limit the result to 20 results so you will get documents 21 to 40 which is desired result.

Upvotes: 0

Related Questions