5

I'am fairly new to angular 4 and I'm trying to make a website that can show users logs. My problem is how can I get new data from database and show it to my angular page without refreshing the page. My friends told me to use ajax, are there any built in solution in angular that can solve my problem? This is my code on the service

import { Injectable } from '@angular/core';
import {Http,Headers} from '@angular/http';
import *  as _ from 'underscore';
import 'rxjs/add/operator/map';
import 'rxjs/add/operator/do';
import 'rxjs/add/operator/toPromise';
import {tokenNotExpired} from 'angular2-jwt';


@Injectable()
export class PagerService {

    authToken:any;
  constructor(private http:Http) { }

  getzip(){
    //gets all the data that matches the users zipcode
        var headers = new Headers();
        this.loadToken();//access token
        headers.append('Authorization',this.authToken);
        headers.append('Content-type','application/json');
        return this.http.get('http://localhost:3000/logs/getByName',{headers:headers})
        .toPromise().then((res) => res.json());
    }


   loadToken(){

        var token = localStorage.getItem('id_token');
        this.authToken = token;
        //this.user = user;
    }

getPager(totalItems: number, currentPage: number = 1, pageSize: number = 10) {
        // calculate total pages
        let totalPages = Math.ceil(totalItems / pageSize);

        let startPage: number, endPage: number;
        if (totalPages <= 10) {
            // less than 10 total pages so show all
            startPage = 1;
            endPage = totalPages;
        } else {
            // more than 10 total pages so calculate start and end pages
            if (currentPage <= 6) {
                startPage = 1;
                endPage = 10;
            } else if (currentPage + 4 >= totalPages) {
                startPage = totalPages - 9;
                endPage = totalPages;
            } else {
                startPage = currentPage - 5;
                endPage = currentPage + 4;
            }
        }

        // calculate start and end item indexes
        let startIndex = (currentPage - 1) * pageSize;
        let endIndex = Math.min(startIndex + pageSize - 1, totalItems - 1);

        // create an array of pages to ng-repeat in the pager control
        let pages = _.range(startPage, endPage + 1);

        // return object with all pager properties required by the view
        return {
            totalItems: totalItems,
            currentPage: currentPage,
            pageSize: pageSize,
            totalPages: totalPages,
            startPage: startPage,
            endPage: endPage,
            startIndex: startIndex,
            endIndex: endIndex,
            pages: pages
        };
    }
}

And this is my component.ts

    import { Component, OnInit } from '@angular/core';
    import {PagerService} from '../../service/pager.service';
    import {Router} from '@angular/router';
    import { Observable } from 'rxjs/Observable';
    import { Http, Headers, RequestOptions, Response } from '@angular/http';
    import *  as _ from 'underscore';


    @Component({
      selector: 'app-messages',
      templateUrl: './messages.component.html',
      styleUrls: ['./messages.component.css']
    })
    export class MessagesComponent implements OnInit {



      constructor(private pagerService:PagerService,
                  private router:Router,
                  private http:Http
                ) { }

        doc:any[];
        // array of all items to be paged
        private allItems: any[];

        // pager object
        pager: any = {};

        // paged items
        pagedItems: any[];

        row:any;

      ngOnInit() {
         this.pagerService.getzip().then(data =>{
         this.allItems = data;this.setPage(1);
         console.log(JSON.stringify(this.allItems.length),"MESSAGES")
    },err=>{console.log(err); return false;});
      }
    setPage(page: number) {
            if (page < 1 || page > this.pager.totalPages) {
                return;
            }
            // get pager object from service
            this.pager = this.pagerService.getPager(this.allItems.length, page);
            // get current page of items
            this.pagedItems = this.allItems.slice(this.pager.startIndex, this.pager.endIndex + 1);
            console.log(this.pager.startIndex,this.pager.endIndex)

          }



    }

And this if my view:

<div *ngIf="allItems && allItems.length <= 0" class="alert alert-dismissible alert-success">
  <button type="button" class="close" data-dismiss="alert">&times;</button>
  <strong>Well done!</strong> There no currently <a href="#" class="alert-link">messages to display</a>.
</div>

<div *ngIf="allItems && allItems.length > 0">
<table class="table table-striped table-hover ">
  <thead>
    <tr>
      <th></th>
      <th>Plate Number</th>
      <th>Date</th>
      <th>Time</th>
      <th>Location</th>
    </tr>
  </thead>
  <tbody >
    <tr *ngFor ="let x of pagedItems;let i = index">
      <td>{{i+(pager.startIndex+1)}}</td>
      <td>{{x.platenumber}}</td>
      <td>{{x.date.month}}-{{x.date.dayN}}-{{x.date.year}}</td>
      <td>{{x.time}}</td>
      <td>{{x.location.street}}</td>
    </tr>
  </tbody>
</table>
</div>

<div class = "text-center">
<!-- pager -->
            <ul *ngIf="pager.pages && pager.pages.length" class="pagination">
                <li [ngClass]="{disabled:pager.currentPage === 1}">
                    <a (click)="setPage(1)">First</a>
                </li>
                <li [ngClass]="{disabled:pager.currentPage === 1}">
                    <a (click)="setPage(pager.currentPage - 1)">Previous</a>
                </li>
                <li *ngFor="let page of pager.pages" [ngClass]="{active:pager.currentPage === page}">
                    <a (click)="setPage(page)">{{page}}</a>
                </li>
                <li [ngClass]="{disabled:pager.currentPage === pager.totalPages}">
                    <a (click)="setPage(pager.currentPage + 1)">Next</a>
                </li>
                <li [ngClass]="{disabled:pager.currentPage === pager.totalPages}">
                    <a (click)="setPage(pager.totalPages)">Last</a>
                </li>
            </ul>
</div>
Nehal
  • 13,130
  • 4
  • 43
  • 59
Ralph Mungcal
  • 117
  • 1
  • 1
  • 13

2 Answers2

6

In an ideal case, there should be a push notification method setup by the server side that tells the client that new data is available.

If that's not available, you can use setInterval() to update your allItems variable, which is hold all the data returned from service. I suggest you make these adjustments in your component.ts:

dataRefresher: any;

ngOnInit() {
  this.getData(true);
  this.refreshData();     
}

getData(setPageFlag){
  this.pagerService.getzip().then(data =>{
    this.allItems = data;
    if(setPageFlag){
      this.setPage(1);
    }
    console.log(JSON.stringify(this.allItems.length),"MESSAGES")
  },
  err => { console.log(err); return false;});
}

refreshData(){
  this.dataRefresher =
    setInterval(() => {
      this.getData(false);
      //Passing the false flag would prevent page reset to 1 and hinder user interaction
    }, 30000);  
}

Refresh time is set to 30s, change it to whatever is good for you :)

You can also add a function to clear the interval and call it on ngOnDestroy:

cancelPageRefresh(){
    if(this.dataRefresher){
        clearInterval(this.dataRefresher);
    }    
}

ngOnDestroy(){
  this.cancelPageRefresh();
}

If you are using OnDestroy, don't forget to import it and add it in class implementation

Jens Habegger
  • 5,266
  • 41
  • 57
Nehal
  • 13,130
  • 4
  • 43
  • 59
  • Im very sorry but can I ask what is a push notification method? Is that same as using Socket.io? – Ralph Mungcal Jul 25 '17 at 14:06
  • You can read in detail [here](https://stackoverflow.com/questions/33687298/how-to-send-push-notification-to-web-browser) – Nehal Jul 25 '17 at 14:17
  • I tried using this solution but all it does is get new data. Can I do something for the actual html page show the new data with reloading the page? – Ralph Mungcal Jul 25 '17 at 14:31
  • 1
    `this.allItems = data;` is setting the newly retrieved data to the variable. Angular automatically updates view with new value of `allItems`. – Nehal Jul 25 '17 at 14:36
  • @Nehal, can you please look into this: https://stackoverflow.com/questions/65371976/how-to-reload-a-component-in-angular-without-reloading-the-whole-page – Tanzeel Dec 19 '20 at 16:49
  • @Nehal, I'm blocked since many days. I need your help. – Tanzeel Dec 19 '20 at 16:49
0

One way to refresh data without reloading the whole HTML page is reassigning the data source in one of Angular's lifecycle hooks. In the below code snippet, to display upto date data I'm using the AfterViewChecked hook. component.ts

ngAfterViewChecked(): void {
this.lstorage = JSON.parse(localStorage.getItem('employee')!);
}
Shekhar
  • 1
  • 2