Ion-refresher is not refreshing page contents

I have this piece of code:

  export class JobsPage {
   jobs: Jobs[]

  constructor(public navCtrl: NavController, private jobsData: JobsData) {
   
       jobsData.load().then(res => {
           this.jobs = res; 
        })
       }
  doRefresh(refresh){

      setTimeout(() => {
       this.jobsData.load().then(res => {
         this.jobs = res;
       }); 
       refresh.complete();
      }, 1000);
     }

As you see I am running the service this.jobsData.load() again in the refresher function, but however the new data is not updated… unless I completely refresh the web page in order to load the new

Without seeing JobData’s internals, have you tried isolating the issue further?

  1. Is doRefresh being called? Always start with the simple question.
  2. Is the load function being called?
  3. If it being called, can I set to some local data that I can track?
  4. That is the res actually? Are you getting that data back that you expect?
  5. Have you set the res to be fake local data and seen the UI update?

Basically, follow the whole process through, checking the validity at each point.

Thank you Chris for the reply… I did what you said, but im confused on how to build a local data in this situation… Also did some research regarding application life hooks, and it seems that the service only fires once the first time, so I tried using

   ionViewWillEnter() 

but still the same. When I log the received data from within the doRefresh(refresh) function… its not being reloaded/updated, it returns back the same data that was fired the first time.

here is my code now , but still having the same problem:

  export class JobsPage {
     jobs: Jobs[]

    constructor(public navCtrl: NavController, public jobsData: JobsData) {}

   ionViewWillEnter(){
      return this.jobsData.load().then(res => {    ////// this returns that data the first time when the application is loaded
        this.jobs = res;
       })
   }

  doRefresh(refresh){

     this.jobsData.load().then(res => {
       this.jobs=res;
      console.log(this.jobs) /// data is not update, still the same
     })
  
    setTimeout(() => {
       this.jobsData.load().then(res => {  /// I am trying to call the service within setTimeout , but still data is not updating
         this.jobs=res;
         refresh.complete(); 
           console.log(this.jobs)
   })  
 }, 6000);
}

this is the html side:

   <ion-header>
     <ion-navbar>
       <ion-title>Jobs</ion-title>
     </ion-navbar>
   </ion-header>

   <ion-content class="card-background-page">
     <ion-refresher (ionRefresh)="doRefresh($event)">
       <ion-refresher-content 
         pullingIcon="arrow-dropdown"
         pullingText="Pull to refresh"
         refreshingSpinner="circles"
         refreshingText="Refreshing...">
       </ion-refresher-content>
      </ion-refresher>

   <ion-card *ngFor="let job of jobs" class="job-card">
   
       /// page content with card-header and card-content

  </ion-card>
</ion-content>

@yasirpanjsheri Maybe the problem is in jobsData.load() that is returning the same data. You said that console.log() showed the same data, so maybe you have to change the load() method in JobsData to be able to return the correct data.

1 Like

Odd are your jobsData.load function looks like this:

load() {
if (this.data) {
return Promise.resolve(this.data);
}

Meaning, there is data, then it will return the stored data and not make the call to the external service to update.

2 Likes

you both are right.

this is the jobsData.load:

  load() {
     if (this.data) {
       return Promise.resolve(this.data);
     }
     return new Promise(resolve => {
     this.http.get(this.jobsApiUrl)
        .map(res => res.json())
        .subscribe(data => {
           this.data = data.data;
           resolve(this.data);
          });
      });
    }

the reason I am using Promise is because this part:

   .subscribe(data => {
           this.data = data.data;
           resolve(this.data);
          });

My API looks like this:

  { data: [{........}, {.........}], meta: pagination:{.....} }

I wanted the data part only… I tried doing this with Observables but I couldn’t access data in the .ts

  load(): Observable<Jobs[]>{
     return this.http.get(this.jobsApiUrl)
    .map(res => <Jobs[]>(res.json()))
    }

Also not to forget…data also has sub objects as well.

When I subscribe to this service:

   ionViewWillEnter(){
     return this.jobsData.load().subscribe(res => {
     this.jobs = res;
     console.log(this.jobs)    //// Object {data: Array[10], meta: Object}
     })
    }

But I receive an error in the html side: *ngFor="let job of jobs"
Cannot find a differ supporting object '[object Object]' of type 'object'. NgFor only supports binding to Iterables such as Arrays

If I change it to this : *ngFor="let job of jobs.data" : Cannot read property 'data' of undefined

OR this in .ts side: console.log(this.jobs.data[0]) ///// property 'data' does not exist on type 'Jobs[]'

Jobs[] is a model (jobs.ts) which contains some of the keys for the data part in the API :

  export interface Jobs {
       id: number;
       position_title: string;
       vacancy_number: string;
       no_of_vacancies: number;
       probation_period: number; 
       .
       .
    }    

Any solution for this , thanx

I solved the problem by just removing

      load() {
        if (this.data) {
          return Promise.resolve(this.data);
        }

But I am interested to know if there is a way to return data using Observables ??

@yasirpanjsheri You showed the problem itself in your post.

Try to change this code:

load(): Observable<Jobs[]>{
    return this.http.get(this.jobsApiUrl)
    .map(res => <Jobs[]>(res.json()))
}

with this:

load(): Observable<Jobs[]>{
    return this.http.get(this.jobsApiUrl)
    .map(res => <Jobs[]>(res.json().data))
}

Have in mid that ngFor needs an array, and res is an object with a property called data that is an array, and probably what you want. You are casting it to Jobs[] in the load method, but it is done incorrectly, because the response is an object with a data array, and not the array itself (you can see it in the log in ionViewWillEnter).

1 Like

A question, Do I really need to have a model like for example (jobs.ts) for getting API data ? Im not even sure why we make one ?

@yasirpanjsheri No, the interface is to help avoid typing errors, autocompletion, make the code easier to understand, and so on, but you don’t need it, although I recommend using types whenever possible (it’s the main reason of using typescript IMO). You could just write:

load(): Observable<any[]>{ ... }

or define the interface explicitly, although it is not a good idea with interfaces with several properties:

load(): Observable<Array<{ id: number; position_title: string; ... }>>{ ... }

For closely related interfaces, sometimes I define more than 1 interface in the same file, to avoiding creating lots of files of interfaces. For instance, my-interface.ts:

export MyInterface1 {
    ...
    options?: MyInterfaceOptions;
}

export MyInterfaceOptions {
    ...
}

export MyInterface2 extends MyInterface1 {
    ...
}
1 Like

i have the same problem. Any solution for refresh new data with ion refresher?

hi there… my problem was in the service.ts itself, as ChrisGriiffith mentioned above
instead of using promise you should use observables or just remove this part of the code:

 load(){
    if(this.data){
           return Promise.resolve(this.data)
    }

so just only:

  load () {
    return new Promise(resolve => {
       this.http.get(.......)
        .map(res => res.json())
     });

work in me :slight_smile:

Is there an horizontal equivalent for ion-scroller?