What is the best way to change components inside pages?

Hello,
I recently started learning both Ionic and Angular.
This might be a stupid question but what’s the best way to change my components inside my pages ?
I mean for instance, if I have a home page where I display a surveys’ list.
Each survey clicked makes my app navigating to /survey/:surveyId

The page would be like this :

There would be a child component which is /question at the middle of the page
This would route automaticaly the URL to /survey/:surveyId/question/:currentQuestionId

When a question would be complete, I only want the “Question” component which is the rounded rect to change. I want to keep the heading title “Survey ID” and the sub-heading “Survey Category + Survey Duration”

My idea was to create the route /survey/:surveyId/question/:currentQuestionId
On question complete, I would have done router.navigate, but this would change the whole view
Or I could change to /survey/:surveyId/question/:nextQuestionId but I would have to clear the backstack and go back to /home if either back button is clicked in the toolbar or physical/virtual back button is clicked (in Android)

If I’m using backstack clearing, is it a good practice for this case ?
Or if I can only change the component, how could I do this?

Thanks,

Awaydrasil,

You have some wrong ideas on how things work in a page in Ionic/Angular. You won’t need to change routes, redraw pages, etc. Instead, you’ll need to just changes some variables, and when they change, what is displayed will change.

I’ve whipped up a little example for you. Hope this helps.

home.page.html:

<ion-header>
  <ion-toolbar>
    <ion-title>
      Survey {{ID}}
    </ion-title>
  </ion-toolbar>
</ion-header>

<ion-content>

  <ion-list>
    <ion-item>
      Category: {{category}}
    </ion-item>
    <ion-item>
      Duration: {{duration}}
    </ion-item>
  </ion-list>

  <ion-card>
    <ion-card-header>
      Question: {{question}}
    </ion-card-header>
    <ion-card-content>
      <ion-list>
        <ion-item button *ngFor="let answer of answers" (click)="answerChosen(answer)">
          {{answer}}
        </ion-item>
      </ion-list>
    </ion-card-content>
  </ion-card>

</ion-content>

home.page.ts:

import { Component } from '@angular/core';

@Component({
  selector: 'app-home',
  templateUrl: 'home.page.html',
  styleUrls: ['home.page.scss'],
})
export class HomePage {

  public ID = 'AnID';
  public category = 'Geograpy';
  public duration = 100;

  public question = '';
  public answers: string[] = [];

  constructor() {

    // Initialization: I'll set the question and answers
    // here just for demonstration.  A better way would
    // be to have a QuestionService which would handle
    // all the details of questions, answers, etc.

    this.question = 'What is the capital of Germany?';
    this.answers = [
      'London',
      'Tokyo',
      'Vienna',
      'Berlin',
      'Amsterdam'
    ];

  }

  answerChosen(answer: string) {
    console.log('User chose answer', answer);
    // do stuff here like, recording if the answer is correct or not,
    // changing to the next question and changing the list of answers,
    // etc.  E.g.,

    this.question = 'What is the longest river in the world?';
    this.answers = [
      'Mississippi',
      'Yangtse',
      'Nile',
      'Amazon',
      'Ganges'
    ];
  }

}

If you create a brand new project and replace home.page.html and home.page.ts with this code, you’ll see that you have the beginnings of what you are looking for. When the user clicks an answer, the answerChosen() function is called, which changes the question and answers variables. When they are changed, Angular updates the page to show the new values.

Now, this demo does not do much: you only see the first question and answers, and then the 2nd question and answers. Once you click the second time, that’s it.

Hope this helps.

Vic

3 Likes

Hello,

Thank you very much for your explanation.
At the beginning I understood this way for things to work. But after, I thought I was wrong to think that changing variables would do the job since I learnt about subscriptions and emitters.
Why would I add subscriptions/subjects if changing variables would be enough ?

Thanks.

I don’t really know what you mean by subscriptions/subjects…

You can add services, which are components that serve data to one or more pages. Then, you can make the pages subscribe to the data so that when the data changes the pages get their copies of the data updated.

That’s what I meant, wasn’t sure of the correct word.
I understood how it works now, thank you very much :slight_smile:

One huge reason is building a single source of truth. Any time you have the same data in more than one place, you have to worry about what happens when they don’t agree. I have developed a habit of moving as much data handling as possible out of pages and into services, at which point the service becomes the most natural holder of truth, and we have a problem (especially acute when more than one page is interested in working with the data) of how to communicate changes to consumers.

RxJS (the “subjects and subscriptions” bit) addresses this problem squarely. The service can expose the data as an Observable, pages can subscribe to it, and then whenever there are changes - even if they are triggered from outside forces that the page doesn’t even know exists - the page is automatically notified, and your app code doesn’t have to do much of anything to reflect them, because that’s what Angular’s change detection is designed to handle.