Dynamic Page Navigation in Ionic 2: A step-by-step guide

I'm currently immersed in a project that involves a series of exercises. When I select an exercise, it takes me to another page where I can watch a video demonstration of that particular exercise. Here's what I have implemented so far:

This is my home.html:

<ion-card *ngIf="oefening1" (click)="navigate(oefening1, oefening2, oefening3, oefening4)">
<img src="assets/img/{{ oefening1 }}.jpg"/>
<ion-card-content>
  <ion-card-title>{{ oefening1 }}</ion-card-title>
  <p>Sets: {{ set1 }}</p>
  <p>Reps: {{ rep1 }}</p>
</ion-card-content>

<ion-card *ngIf="oefening2" (click)="navigate(oefening2, oefening1, oefening3, oefening4)">
    <img src="assets/img/{{ oefening2 }}.jpg"/>
    <ion-card-content>
      <ion-card-title>{{ oefening2 }}</ion-card-title>
      <p>Setjes: {{ set2 }}</p>
      <p>Herhalingen: {{ rep2 }}</p>
    </ion-card-content>
  </ion-card>

This is the navigate function in home.ts:

navigate(exercise, exercise2, exercise3, exercise4){
  this.navCtrl.push(ExercisePage, {
            clickedExercise: exercise,
            secondExercise: exercise2,
            thirdExercise: exercise3,
            fourthExercise: exercise4
    });
  }

This is my exercise.html:

<ion-content padding overflow-scroll="true">
  <ion-grid>
  <ion-row>
    <ion-col col-12>
      <div (click)="playVid()" padding-bottom>
        <img *ngIf="fullPath" [src]="fullPath"/>
      </div>
      <div text-center>
        <button ion-button block [disabled]="!disabledBtn">Block Button</button>
        <button ion-button round (click)="nextExercise()">Complete</button>
      </div>
    </ion-col>
  </ion-row>
  </ion-grid>
</ion-content>

And here's the exercise.ts:

export class ExercisePage {
  public clickedExercise: any;
  public secondExercise: any;
  public thirdExercise: any;
  public fourthExercise: any;
  public fullPath: string;
  public disabledBtn: boolean;

  constructor(public navCtrl: NavController, private streamingMedia: StreamingMedia, public params:NavParams) {
    this.clickedExercise = params.get("clickedExercise");
    this.secondExercise = params.get("secondExercise");
    this.thirdExercise =  params.get("thirdExercise");
    this.fourthExercise = params.get("fourthExercise");
    this.disabledBtn = false;
  }

  playVid(){
     console.log('video completed');

     setTimeout(() => {
      this.disabledBtn = true;
    }, 10000);

    // Playing a video.
    let options: StreamingVideoOptions = {
        successCallback: () => { console.log('Video played') },
        errorCallback: (e) => { console.log('Error streaming') },
        orientation: 'portrait'
    };

    this.streamingMedia.playVideo('http://www.sylvanreinieren.com/fysioWebapp/videos/'+ this.clickedExercise + '.mp4', options);
  }

  ionViewWillEnter() {
    this.fullPath = "assets/img/" + this.clickedExercise + ".jpg";
    // console.log('secondExercise:',this.secondExercise, 'ThirdExercise: ', this.thirdExercise, 'Fourth: ', this.fourthExercise);
  }

  nextExercise(){
    this.clickedExercise = this.secondExercise;
    this.secondExercise = this.thirdExercise;
    this.thirdExercise = this.fourthExercise;

    this.navCtrl.push(ExercisePage, {
        clickedExercise: this.secondExercise,
        secondExercise: this.thirdExercise,
        thirdExercise: this.fourthExercise
    });

    console.log('nextExercise', this.clickedExercise);
  }
}

Essentially, I aim to display the next exercise when the "Next" button is clicked, progressing through each exercise in turn and returning to the home page once all exercises are completed. Unfortunately, it seems to be skipping the second exercise. Any suggestions on how to resolve this issue would be greatly appreciated.

Answer №1

As mentioned earlier, I believe it would be more beneficial for you to implement this in a slider format. Why?

  • You are already aware of the number of exercises, which in this case is 4.
  • Every navCtrl.push creates a new page instead of updating an existing one.
  • If you eventually expand to have 20 exercises per page, it wouldn't be ideal for users to click back 20 times to exit the exercises.
  • It's simple to manipulate.

In this instance, my focus will solely be on the exercises page. If you wish to make changes to the Home page to enhance its dynamics, we can certainly address that too.

Exercise.html

<ion-content overflow-scroll="true">
    <ion-slides>
        <ion-slide *ngFor="let ex of allExercises; let i = index">
            <ion-grid>
                <ion-row>
                    <ion-col col-12>
                        <div (click)="playVideo(ex.exercise)" padding-bottom>
                            <img [src]="ex.path" />
                        </div>
                        <div text-center>
                            <!-- disabled if it's the first exercise -->
                            <button *ngIf="i == 0" ion-button round (click)="previousExercise()">Previous</button>
                            <button ion-button block [disabled]="!disabledBtn">Block Button</button>
                            <!-- unavailable if it's the last exercise -->
                            <button *ngIf="i == ;" ion-button round (click)="nextExercise()">Finish</button>
                        </div>
                    </ion-col>
                </ion-row>
            </ion-grid>
        </ion-slide>
    </ion-slides>
</ion-content>

Exercises.ts

import { Slides } from 'ionic-angular';
export class ExercisePage {
    public fullPath: string;
    public disabledBtn: boolean;
    public allExercises: any[] = []; // STORES ALL EXERCISES

    constructor(
        public navCtrl: NavController,
        private streamingMedia: StreamingMedia,
        public params: NavParams,
        public slides: Slides
    ) {
        // SETTING UP EXERCISES AND IMAGE PATHS ON PAGE LOAD
        this.allExercises.push({
            exercise: params.get("clickedExercise"),
            path: 'assets/img/' + params.get("clickedExercise") + '.jpg'
        });
        this.allExercises.push({
            exercise: params.get("secondExercise"),
            path: 'assets/img/' + params.get("secondExercise") + '.jpg'
        });
        this.allExercises.push({
            exercise: params.get("thirdExercise"),
            path: 'assets/img/' + params.get("thirdExercise") + '.jpg'
        });
        this.allExercises.push({
            exercise: params.get("fourthExercise"),
            path: 'assets/img/' + params.get("fourthExercise") + '.jpg' 
        });
        this.disabledBtn = false;

        // prevent swipe to change page
        slides.lockSwipes(true);
    }

    playVideo(exercise: string) {
        console.log('video completed');

        setTimeout(() => {
            this.disabledBtn = true;
        }, 10000);

        // Play video function.
        let options: StreamingVideoOptions = {
            successCallback: () => { console.log('Video played') },
            errorCallback: (e) => { console.log('Error streaming') },
            orientation: 'portrait'
        };

        this.streamingMedia.playVideo('http://www.sylvanreinieren.com/fysioWebapp/videos/' + exercise + '.mp4', options);
    }

    nextExercise() {
        this.slides.lockSwipes(false);
        this.slides.slideNext();
        this.slides.lockSwipes(true);
    }

    previousExercise() {
        this.slides.lockSwipes(false);
        this.slides.slidePrev();
        this.slides.lockSwipes(true);
    }
}

Create an object to store all exercises.

Add each exercise and image path to this object (assuming an exercise is just its name).

Import the Slides component and lock swiping to disable changing slides through swipe gestures (you can enable this if desired).

In your HTML, use ion-slides with ion-slide iterating through all exercises using *ngFor.

The playVideo() function plays the respective video for the selected exercise.

I hope this explanation helps.

Similar questions

If you have not found the answer to your question or you are interested in this topic, then look at other similar questions below or use the search

It is crucial to include the _id field in the findOneAndUpdate operation

In my code, I have a function that updates documents in mongoDB. After manipulating the data, I use mongoose's findOneAndUpdate function to update the desired document. To fetch only specific fields from the saved data, I set new:true and define an ob ...

Allow for various index.html files to be supported based on the environment, using both nginx and Angular

In my Angular 5 project, I had to make changes to the index.html file based on environment builds. To do this, I included multiple declarations of "apps" in the angular-cli.json file. Specifically, --app=0 contains development environments while --app=1 co ...

I am looking to personalize the AddedToCartDialogComponent with the selector cx-added-to-cart-dialog

I've been trying to tailor the AddedToCartDialogComponent by incorporating new elements into the dialog window. Despite closely following Spartacus documentation, I am unable to see any changes taking effect. Running on Spartacus version 4, here is a ...

Dealing with null-safe operators issues has been a challenge for me, especially while working on my Mac using

Hey everyone! I'm encountering errors when using null sage operators in TypeScript. Can someone help me figure out how to solve this issue? By the way, I'm working on Visual Studio Code for Mac. https://i.stack.imgur.com/huCns.png ...

Production environment causing issues with router.url functionality

Encountering an issue in production (server with Apache) with the Router component of Angular version 4.4.6. Below is the code snippet: import { Component, OnInit } from '@angular/core'; import { ActivatedRoute, Params, Router} from '@angul ...

The FOR UPDATE clause is not functioning as intended in the SELECT query

I have been working on isolating my database to prevent multiple servers from reading or updating data in the same row. In order to achieve this, I have structured my query like so: SELECT * FROM bridge_transaction_state as bridge WHERE bridge.state IN (&a ...

Tips for testing nested subscribe methods in Angular unit testing

FunctionToTest() { this.someService.method1().subscribe((response) => { if (response.Success) { this.someService.method2().subscribe((res) => { this.anotherService.method3(); }) } }); } Consider the following scenario. ...

Encountering a problem with SCSS variable declaration in React JavaScript when converting to TypeScript

Currently, I am in the process of converting a JavaScript React project to TypeScript. Everything is progressing smoothly, except for the issue with the SCSS files. In our SCSS files, we utilize variables which have been working fine in the JavaScript ver ...

Encountered an error while iterating through an array in Angular: "Cannot access property at index

I've encountered an error while trying to loop through an array of items and pushing them to another array. I am able to access the items at index "0", but still facing the mentioned error. Below is the code snippet for reference: createReportFormu ...

A function in Typescript is created to handle diverse input types in a generic manner

My goal is to create a function that can handle various input types for abstraction purposes. type ContentA = string type ContentB = number type InputA = { name: 'method_a' content: ContentA } type InputB = { name: 'method_b' con ...

Exploring Recursive Types in TypeScript

I'm looking to define a type that can hold either a string or an object containing a string or another object... To achieve this, I came up with the following type definition: type TranslationObject = { [key: string]: string | TranslationObject }; H ...

Controlling the visibility of an element in Angular2 by toggling it based on an event triggered by a

Within my component, there is a child element: <fb-customer-list (inSearchMode)="listIsInSearchMode = event$"></fb-customer-list> This child element emits an event that contains a boolean value to indicate when it changes modes. In the paren ...

Experimenting with Typescript, conducting API call tests within Redux actions, mimicking classes with Enzyme, and using Jest

I am facing an issue where I need to mock a class called Api that is utilized within my redux actions. This class is responsible for making axios get and post requests which also need to be mocked. Despite following tutorials on how to mock axios and class ...

When examining two arrays for similarities

I am dealing with two arrays within my component arr1 = ["one", "two"] arr2 = ["one", "two"] Within my HTML, I am utilizing ngIf in the following manner *ngIf="!isEnabled && arr1 != arr2" The isEnabled condition functions as expected, however ...

Can the hexadecimal value from an input type color be extracted and used to populate form fields that will then be displayed in a table after submission?

Hello everyone, I'm new to this platform and seeking guidance on how to improve my post! I recently created a CRUD app using Angular. It consists of a basic form with 4 fields, a color picker using input type='color', and a submit button. U ...

Linking an npm package to a custom TypeScript definitions file in a local directory

Currently, I am utilizing an npm package called "foo" for my project development. However, I want to link this package with a local TypeScript definitions file that is committed along with the project files. My intention is not to release this definitions ...

Altering the inner HTML content of a div using the ID within an Angular component function

Attempting to change the inner HTML content of a div using its id with another div in an Angular component method. Successfully calling the populateEndpointHomeContent() method and retrieving the content, but encountering issues with subsequent content. Th ...

What are the steps for utilizing the watch feature in Vue.js with TypeScript?

Currently, I am looking to convert this JavaScript script into TypeScript. However, I require the syntax for watchers. export default { props: ['branch_id'], watch: {} } ...

Failed to execute start script 'ng serve' in npm start

Let me make it clear: I'm brand new to AngularJS and pretty much any Web Technology. I consider myself a novice in the realm of Web Development. I attempted to install AngularJS, and truth be told, after numerous "Mysterious Button Clicks", I might ...

Protect the integrity of string output while maintaining the original spacing

When working with Angular, I often utilize the string output method like this: <div>{{stringWithValue}}</div> However, a problem arises when my string is either just a whitespace or empty - the value does not get rendered. To address this issu ...