Sorakthun Ly Sorakthun Ly - 3 months ago 230
TypeScript Question

Re-initialize constructor to refresh page after data update on another page - Ionic2

The app is a simple workout entry tool. It does basic API call for CRUD operations. App Display

I can't reload the Workout Tab after a new entry is created and stored to the database. I was able to manipulate NavController to set root for it to display the updated data but it's only under the Add Workout tab. Workouts updated in Add Workout tab When I tab back to Workout tab. It displays the result as the first image attached.

I presume this is because the constructor and NgOnInit are initialized only once. How can I get around this?

This is the code for the Workout tab.

export class WorkoutPage {
navCtrl;
workoutService;
workouts;

static get parameters() {
return [NavController, WorkoutService];
}

constructor(navCtrl, workoutService) {
this.navCtrl = navCtrl;
this.workoutService = workoutService;
this.workoutService.getWorkouts().subscribe(workouts => {
this.workouts = workouts;
})
}

ngOnInit() {
this.workoutService.getWorkouts().subscribe(workouts => {
this.workouts = workouts;
})
}

workoutSelected(event, workout) {
this.navCtrl.push(WorkoutdetailPage, {
workout: workout
})
}
}


This is how I do setRoot after new entry is added to the database.

onSubmit() {
var workout = {
title: this.title,
note: this.note,
type: this.type
}

this.workoutService.addWorkout(workout)
.subscribe(data => {
this.result = data;
}, err => console.log(err),
() => console.log("Workout added"));

this.navCtrl.setRoot(WorkoutPage);
}


I really need a way to refresh data on the Workout page. Your help is very much appreciated.

Answer

You can do that by using an observable, so every time a new item is added, the component where you have the submit method could tell the component that shows the list that it needs to reload the list of items. In order to do that we can use a pretty simple shared service like this one:

@Injectable()
export class SyncService { 

  private newItemObserver: any;
  public newItem: any;

  constructor(){
    this.newItemObserver = null;
    this.newItem = Observable.create(observer => {
        this.newItemObserver = observer;
    });
  }

  public updateListOfItems() {
      // This will let the subscribers now that they must reload the list of items
      this.newItemObserver.next(true);
  }
}

And then, in the component where you add the new item:

constructor(private syncService: SyncService, ...) {
  //...
}

onSubmit() {
  var workout = {
    title: this.title,
    note: this.note,
    type: this.type
   }

  this.workoutService.addWorkout(workout)
    .subscribe(data => {
        this.result = data;

        // Let the subscribers know that they need to update the list of items
        this.syncService.updateListOfItems();


        // Navigate to the corresponding tab
        this.navCtrl.setRoot(WorkoutPage);

    }, err => console.log(err),
    () => console.log("Workout added"));
}

And finally in the component where you show the list of items, you just need to subscribe to that observable like this:

export class WorkoutPage {
  navCtrl;
  workoutService;
  workouts;
  syncService;

static get parameters() {
    return [NavController, WorkoutService, SyncService];
}

constructor(navCtrl, workoutService, syncService) {
  this.navCtrl = navCtrl;
  this.workoutService = workoutService;
  this.syncService = syncService;

  // Subscribe to the observable to know when to reload the list of items
  this.syncService.newItem.subscribe((boolValue) => {
    this.getListOfWorkouts();
  });
}

ngOnInit() {
  this.getListOfWorkouts();
}

getListOfWorkouts(){
  this.workoutService.getWorkouts().subscribe(workouts => {
    this.workouts = workouts;
  });
}

workoutSelected(event, workout) {
  this.navCtrl.push(WorkoutdetailPage, {
      workout: workout
  })
}
}