Ionic and Angular: Infinite Scrolling with RESTful APIs
Wall Script
Wall Script
Monday, November 13, 2017

Ionic and Angular: Infinite Scrolling with RESTful APIs

We have seen series of posts on developing a mobile application using Ionic and AngularJS. One of my previous articles which deal with insertion and deletion of posts using RESTful API. Similarly, today’s post makes use of RESTful API. These days, a single page web applications are most commonly used ones, because of which there is a need to show loads of data on the same page as we keep on scrolling. This infinite scrolling avoids pagination system.

Infinite Scrolling using Ionic and Angular with RESTful APIs


Live Demo


Video Tutorial
Infinite Scrolling using Ionic and Angular with RESTful APIs


Database Design
To build the user social login system, you have to create a user table.

Users
User table contains all the users social details.
CREATE TABLE users(
user_id int AUTO_INCREMENT PRIMARY KEY,
email varchar(300),
name varchar(200),
provider varchar(50),
provider_id varchar(200),
provider_pic varchar(200),
token varchar(500));

Feed
This table contains user daily updates.
CREATE TABLE feed(
feed_id int PRIMARY KEY AUTO_INCREMENT,
feed text,
user_id_fk int,
created int
);


home.html
Go to your angular project and include ion-infinite-scroll tag with doInfinite function. This HTML tag will trigger doInfinite function when you reach page scroll down.
<ion-content padding>
<h2>Welcome to {{userDetails.name}}</h2>
 <ion-item id="udpateBox">
      <textarea #updatebox [(ngModel)]="userPostData.feed" autofocus></textarea>
    <ion-row>
       <button ion-button color="energy" (click)="feedUpdate()">Update</button>
    </ion-row>
</ion-item>

<ion-card *ngFor="let item of dataSet; let msgIndex = index">
 <ion-item>
    <ion-icon name="trash" item-right (click)="feedDelete(item.feed_id, msgIndex)"></ion-icon>
    <ion-card-content>
    <p [innerHTML]="item.feed | linky"></p>
    <span>{{this.converTime(item.created) | amTimeAgo}}</span>
    </ion-card-content>
</ion-item>
</ion-card>

<ion-infinite-scroll (ionInfinite)="$event.waitFor(doInfinite())">
   <ion-infinite-scroll-content></ion-infinite-scroll-content>
</ion-infinite-scroll>

</ion-content>

home.ts.
In getFeed() function we need to set the last created timestamp for new scroll data. Explained more on video tutorial
import { Component } from "@angular/core";
import { NavController, App, AlertController } from "ionic-angular";
import { AuthService } from "../../providers/auth-service";
import { Common } from "../../providers/common";

@Component({ selector: "page-home", templateUrl: "home.html" })
export class HomePage {
      public userDetails: any;
      public resposeData: any;
      public dataSet: any;
   
     userPostData = {
        user_id: "",
        token: "",
        feed: "",
        feed_id: "",
        lastCreated: ""
     };

constructor(
   public common: Common,
   private alertCtrl: AlertController,
   public navCtrl: NavController,
   public app: App,
   public authService: AuthService) {
const data = JSON.parse(localStorage.getItem("userData"));
   this.userDetails = data.userData;
   this.userPostData.user_id = this.userDetails.user_id;
   this.userPostData.token = this.userDetails.token;
   this.userPostData.lastCreated = "";
   this.getFeed();
}

getFeed() {
  this.common.presentLoading();
  this.authService.postData(this.userPostData, "feed").then(
  result => {
     this.resposeData = result;
     if (this.resposeData.feedData) {
        this.common.closeLoading();
        this.dataSet = this.resposeData.feedData;
        // Data set length
        const dataLength = this.resposeData.feedData.length;
        this.userPostData.lastCreated = this.resposeData.feedData[dataLength - 1].created;
      } else {
       console.log("No data");
     }
},
err => {
   //Connection failed message
}
);
}

feedUpdate() {
// API update feed
}

feedDelete(feed_id, msgIndex) {
// API delete feed
}

doInfinite(e): Promise<any> {
console.log("Begin async operation");
   return new Promise(resolve => {
      setTimeout(() => {
         // API Connection for more updates
         resolve();
       }, 500);
      });
}

converTime(time) {
   let a = new Date(time * 1000);
   return a;
}

backToWelcome() {
   const root = this.app.getRootNav();
   root.popToRoot();
}

logout() {
//Api Token Logout
   localStorage.clear();
   setTimeout(() => this.backToWelcome(), 1000);
}
}



Download PHP Restul Project
$git clone https://github.com/srinivastamada/PHP-Slim-Restful.git


PHP RESTful API index.php
Improved feed() function with limited user feed results. If lastCreated is present, we need to get the data based on last timestamp.
<?php
require 'config.php';
require 'Slim/Slim.php';


\Slim\Slim::registerAutoloader();
$app = new \Slim\Slim();


$app->post('/login','login'); /* User login */
$app->post('/signup','signup'); /* User Signup */
$app->post('/feed','feed'); /* User Feeds */
$app->post('/feedUpdate','feedUpdate'); /* User Feeds */
$app->post('/feedDelete','feedDelete'); /* User Feeds */
//$app->post('/userDetails','userDetails'); /* User Details */


$app->run();


/************************* USER LOGIN *************************************/
/* ### User login ### */
function login() {
// ....
}


/* ### User registration ### */
function signup() {
// ....
}



/* ### internal Username Details ### */
function internalUserDetails($input) {
// ....
}


function feed(){
$request = \Slim\Slim::getInstance()->request();
$data = json_decode($request->getBody());
$user_id=$data->user_id;
$token=$data->token;
$lastCreated = $data->lastCreated;
$systemToken=apiToken($user_id);
try {
     if($systemToken == $token){
       $feedData = '';
       $db = getDB();
     if($lastCreated){
         $sql = "SELECT * FROM feed WHERE user_id_fk=:user_id AND created < :lastCreated ORDER BY feed_id DESC LIMIT 5";
        $stmt = $db->prepare($sql);
        $stmt->bindParam("user_id", $user_id, PDO::PARAM_INT);
        $stmt->bindParam("lastCreated", $lastCreated, PDO::PARAM_STR);
}
else{
       $sql = "SELECT * FROM feed WHERE user_id_fk=:user_id ORDER BY feed_id DESC LIMIT 5";
       $stmt = $db->prepare($sql);
       $stmt->bindParam("user_id", $user_id, PDO::PARAM_INT);
}
$stmt->execute();
$feedData = $stmt->fetchAll(PDO::FETCH_OBJ);
$db = null;
if{
     echo '{"feedData": ' . json_encode($feedData) . '}';
}
else{
    echo '{"feedData": ""}';
}
} else{
echo '{"error":{"text":"No access"}}';
}
} catch(PDOException $e) {
     echo '{"error":{"text":'. $e->getMessage() .'}}';
}


}


function feedUpdate(){
// ...
}


function feedDelete(){
// ...
}
?>



home.ts
Here doInfinite function makes an API call with lastCreated. If the feed response with empty data, it sets the noRecords values as true.
import { Component } from "@angular/core";
import { NavController, App, AlertController } from "ionic-angular";
import { AuthService } from "../../providers/auth-service";
import { Common } from "../../providers/common";

@Component({ selector: "page-home", templateUrl: "home.html" })
export class HomePage {
     public userDetails: any;
     public resposeData: any;
     public dataSet: any;
     public noRecords: boolean;
     userPostData = {
        user_id: "",
        token: "",
        feed: "",
        feed_id: "",
        lastCreated: ""
     };

constructor(
public common: Common,
private alertCtrl: AlertController,
public navCtrl: NavController,
public app: App,
public authService: AuthService) {
     const data = JSON.parse(localStorage.getItem("userData"));
     this.userDetails = data.userData;
     this.userPostData.user_id = this.userDetails.user_id;
     this.userPostData.token = this.userDetails.token;
     this.userPostData.lastCreated = "";
     this.noRecords = false
     this.getFeed();
}

getFeed() {
//...
}

feedUpdate() {
//...
}

feedDelete(feed_id, msgIndex) {
//...
}

doInfinite(e): Promise<any> {
console.log("Begin async operation");
   return new Promise(resolve => {
   setTimeout(() => {
      this.authService.postData(this.userPostData, "feed").then(
      result => {
         this.resposeData = result;
         if (this.resposeData.feedData.length) {
            const newData = this.resposeData.feedData;
            this.userPostData.lastCreated = this.resposeData.feedData[newData.length - 1].created;

     for (let i = 0; i < newData.length; i++) {
        this.dataSet.push(newData[i]);
     }
} else {
    this.noRecords = true;
     console.log("No user updates");
}
},
err => {
//Connection failed message
}
);
resolve();
}, 500);
});
}

converTime(time) {
let a = new Date(time * 1000);
return a;
}

backToWelcome() {
//...
}

logout() {
//...
}
}

home.html
Now controlling HTML tag with noRecords values. No records block presents when the noRecords values is true and it stops infinte scrolling action.
<ion-card *ngFor="let item of dataSet; let msgIndex = index">
<ion-item>
   <ion-icon name="trash" item-right (click)="feedDelete(item.feed_id, msgIndex)"></ion-icon>
<ion-card-content>
   <p [innerHTML]="item.feed | linky"></p>
   <span>{{this.converTime(item.created) | amTimeAgo}}</span>
</ion-card-content>
</ion-item>
</ion-card>

<ion-card *ngIf="noRecords">
 <ion-item>
   No Records
  </ion-item>
</ion-card>

<ion-infinite-scroll (ionInfinite)="$event.waitFor(doInfinite())" *ngIf="!noRecords">
   <ion-infinite-scroll-content></ion-infinite-scroll-content>
</ion-infinite-scroll>
web notification

19 comments:

  1. Which code editing software you used.

    ReplyDelete
  2. Uncaught SyntaxError: Unexpected token <
    error in check demp

    ReplyDelete
  3. 1. my feed cant get data if use url api to webserver. but if using localhost xampp my feed can get data
    2. my infinite scroll's not work

    is that bug sir? thank you... your tutorial's very usefull

    ReplyDelete
  4. Srinivas i saw in the tutorial that except from these files on Github i have a add other files on XAMPP? Is that to connect the database with the ionic project? Where can i find these files?

    ReplyDelete
  5. Srinivas, when i try to simulate i am getting Cannot Find module? I forgot to install somehting?

    Severity Code Description Project File Line Suppression State
    Error TS2307 Cannot find module '@angular/core'. ionic-restful-authentication-master (tsconfig project) C:\Users\Simon\Cookies\Desktop\Various Scripts\ioniclast\ionic-restful-authentication-master\src\pages\login\login.ts 1 Active
    Error Error: Current working directory is not a Cordova-based project. ionicLast1 1
    Error TS2307 Cannot find module 'ionic-angular'. ionic-restful-authentication-master (tsconfig project) C:\Users\Simon\Cookies\Desktop\Various Scripts\ioniclast\ionic-restful-authentication-master\src\app\app.component.ts 2 Active
    Error TS2307 Cannot find module 'ionic-angular'. ionic-restful-authentication-master (tsconfig project) C:\Users\Simon\Cookies\Desktop\Various Scripts\ioniclast\ionic-restful-authentication-master\src\app\app.module.ts 3

    ReplyDelete
    Replies
    1. Delete node_modules and platform folders and execute (npm install)

      Delete
    2. OK DID THAT. Isn't a Cordova Based project

      Severity Code Description Project File Line Suppression State
      Error Error: Current working directory is not a Cordova-based project. ioniclast 1
      Error Adding the Cordova platform failed ioniclast 1

      Delete
    3. hello Srinivas i followed the steps
      $ git clone https://github.com/srinivastamada/ionic-restful-authentication.git
      $ cd ionic-restful-authentication
      $ npm install
      $ ionic serve

      All good but how do i make it connect to my phpmyadmin
      What should i do? Any tutorial?

      Delete
    4. Please install XAMPP for PHP APIs.

      Delete
    5. Sorry Srinivas i meant when you Update something it goes on your Database right? There is not connection to my database

      Delete
  6. On visual studio i did Project>Create Project from existing Files>Apache/Cordova>'Put the folder i downloaded from GitHub', 'Named the Project'>'And then on DEBUG AND SIMULATE'>
    I am getting an error Procect is not a Cordova based

    ReplyDelete
    Replies
    1. Try to update your ionic and cordova versions

      $ sudo npm install -g ionic cordova

      Delete
    2. I did i use
      ionic 3.18.0
      cordova 7.1.0

      The PHP restful API is on C:\xampp\htdocs\PHP-Slim-Restful-master

      and the Ionic files on C:\Users\Simon\Cookies\Desktop\Various Scripts\ioniclast

      what i am doing wrong?

      Delete
    3. Hello Srinivas i am getting an error: Node Sass does not yet support your current environments: Windows 64-bit with Unsupported runtime(59) What should i do?

      Delete
    4. sudo npm install --save-dev --unsafe-perm node-sass

      Delete
  7. Hello Srinivas the project opens on http://localhost:8100/ but i don't know how to open the files on visual studio, on the inspector chrome://devtools/. I have downloaded them when i did git clone https://github.com/srinivastamada/ionic-restful-authentication.git right? How may i did them on visual studio?

    ReplyDelete

  8. I’ve been following your blog from few days.
    Your latest post is fantastic and resonated with me. I thought it was something my audience would appreciate,
    Thanks

    ReplyDelete

mailxengine Youtueb channel
Make in India
X