[PROBLEM] ionViewDidLeave / WillLeave fires only one time?


#1

Hello people, i have a problem with which I hope you can help me.

I have an application that connects to the api of soundcloud and performs audio streaming. When the user presses the play / pause button, it verifies if the audio is playing, pauses it and otherwise resumes it.
I also have a stop button with its respective method.

Well, the problem comes when I pop () from this page. I have an ionViewDidLeave () event that calls the stop () method to stop the audio.
But then when I return to the same page, I press the button to play and play correctly, but then if I press to pause, the audio does not pause. And if I go back to a previous page (I pop ()) the audio never stops.

It looks as if the event does not fire again. But I do not know, because it strikes me that neither pause the audio after having left the page and reentered.

Any ideas? Can it be a jquery problem?

Is there any way to completely destroy the page when exiting and “instantiating” a new one when push () is done? Because it looks like the page is being cached

Thanks in advance


#2

Show us your component code :wink:


#3

player.ts:

import { Component } from '@angular/core';
import { NavController, NavParams } from 'ionic-angular';
import * as $ from 'jquery';

import { SoundCloud } from '../../providers/sound-cloud';

declare var SC;

interface User {
    permalink_url: string;
    username: string;
}

interface Track {
    id: number;
    title: string;
    artwork_url: string;
    permalink_url: string;
    user: User;
}

@Component({
    selector: 'page-player',
    templateUrl: 'player.html'
})
export class PlayerPage {
    readonly FIRST_AUDIO: number = 0;
    readonly PLAYER_TAG_INDEX: number = 0;
    readonly AUDIO_START: number = 0;
    readonly PLAY_BUTTON_IMG: string = 'img/play100.png';
    readonly PAUSE_BUTTON_IMG: string = 'img/pause100.png';

    readonly MI_USER_ID: number = 'mi soundcloud user id';


    player: any;
    audio: any;  //navParams
    duration: any; //navParams
    trackInfoForView: {
        src: string,
        duration: number,
        currentTime: number,
        formatedTime: string,
        percent: number;
    };
    tracks: any[] = [];
    playTrackIndex: number = 0;
    soundCloudCurrentTrack: any;

    constructor(
        public navCtrl: NavController,
        private navParams: NavParams,
        public soundCloud: SoundCloud
    ) {
        if (this.navParams.get('audio')) {
            this.audio = this.navParams.get('audio');
            this.duration = this.navParams.get('duration');
            console.log(this.audio.title + ' dura: ' + this.duration.time + ' min.');
        }

        this.trackInfoForView = {
            src: '',
            duration: 0,
            currentTime: 0,
            formatedTime: '00:00',
            percent: 0
        };
    }

    ionViewDidEnter(): void {
        let loadSC = setTimeout(() => {
            this.allTracks();
        }, 500);
    }

    ionViewDidLeave(): void {
        this.stopAudio();
    }

    public allTracks(): any {
        SC.get(`/users/${this.MI_USER_ID}/tracks/`, {
            filter: 'public'
        }).then((tracks) => {
            console.log(tracks);

            this.tracks = tracks;

            console.log("Playing " + tracks.length + " tracks");

            this.startStreaming();
        });
    }

    startStreaming(): void {
        this.soundCloudCurrentTrack = this.tracks[this.playTrackIndex];

        console.log("Playing track " + this.playTrackIndex);
        console.log(this.soundCloudCurrentTrack);

        SC.stream('/tracks/' + this.soundCloudCurrentTrack.id).then((player) => {

            this.player = player;
            console.log(this.soundCloudCurrentTrack.duration);

            if (this.playTrackIndex > this.FIRST_AUDIO) {
                player.play();
            }

            player.on('buffering_start', () => {
                console.log('buffering...');
            });

            player.on('buffering_end', () => {
                console.log('party!');
            });

            player.on('time', () => {
                this.updateTrackTime();
                this.updateTrackPercent();
            });

            player.on('finish', () => {

                if (this.playTrackIndex < this.tracks.length -1) {
                    this.playTrackIndex ++;
                } else {
                    this.playTrackIndex = 0;
                }

                console.log('time to move on...');
                this.startStreaming();
            });
        });
    }

    updateTrackTime(): void {
        let currentTime = this.player.currentTime() / 1000;
        this.trackInfoForView.formatedTime = this.formatTime(currentTime);
    }

    updateTrackPercent(): void {
        this.trackInfoForView.percent = Math.floor((this.player.currentTime() * 100) / this.soundCloudCurrentTrack.duration);
    }

    formatTime(seconds: number): string {
        let minutes: any = Math.floor(seconds / 60);
        let secs: any = Math.floor(seconds % 60);

        if (minutes < 10) {
            minutes = '0' + minutes;
        }
        if (secs < 10) {
            secs = '0' + secs;
        }

        return minutes +  ':' + secs;
    }

    togglePlayPause(): void {
        if (this.player) {

            let $imageSource = $("#playPauseButton img");

            if (this.player._isPlaying) {
                this.player.pause();
                $imageSource.attr("src", this.PLAY_BUTTON_IMG);
            } else {
                this.player.play();
                $imageSource.attr("src", this.PAUSE_BUTTON_IMG);
            }
        } else {
            let autoClick = setTimeout(() => {
                $("#playPauseButton").trigger("click");
                clearTimeout(autoClick);
            },1500)
        }
    }

    stopAudio(): void {

        if (this.player) {
            let $imageSource = $("#playPauseButton img");

            this.player.pause();
            this.player.seek(this.AUDIO_START);
            $imageSource.attr("src", this.PLAY_BUTTON_IMG);
        }
    }
}

soundCloud.ts (initializes SC object):

    import { Injectable } from '@angular/core';
    import { Platform } from 'ionic-angular';
    import { Http } from '@angular/http';
    import 'rxjs/add/operator/map';

    declare var SC;

    interface User {
        permalink_url: string;
        username: string;
    }

    interface Track {
        id: number;
        title: string;
        artwork_url: string;
        permalink_url: string;
        user: User;
    }

    @Injectable()
    export class SoundCloud {

        readonly MI_USER_ID: number = there is my number;

        private clientId: string = 'mi private soundcloud id string';

        constructor(
            public http: Http,
            private platform: Platform
        ) {

            this.platform.ready().then(() => {
                SC.initialize({
                    client_id: this.clientId,
                    redirect_uri: 'http://example.com/callback'
                });
            });
        }
    }

#4

player.html:

<div id="playerContainer">
        <button id="stopButton" (click)="stopAudio()">
            <img src="img/stop100.png" width="50">
        </button>
        <div id="radialProgress">
            <div class="c100 p{{ trackInfoForView.percent }}">
                <span>{{ trackInfoForView.formatedTime }}</span>
                <div class="slice">
                    <div class="bar"></div>
                    <div class="fill"></div>
                </div>
            </div>
        </div>
        <button id="playPauseButton" (click)="togglePlayPause()">
            <img src="img/play100.png" width="50">
        </button>
    </div>

#5

could you try to move your constructor code to the ionViewWillEnter hook?

if (this.navParams.get('audio')) {
            this.audio = this.navParams.get('audio');
            this.duration = this.navParams.get('duration');
            console.log(this.audio.title + ' dura: ' + this.duration.time + ' min.');
        }

        this.trackInfoForView = {
            src: '',
            duration: 0,
            currentTime: 0,
            formatedTime: '00:00',
            percent: 0
        };

I think you should reset everything if you reenter the component.

You are using the same PlayPage for each track like a detail page?
Then the PlayerPage instance should be cached and reused everytime. Even if the nav params changed

So it looks okay to me. Can not see any failure in your code.


#6

Thanks for the help!

Yes it’s like a detail page. I use the same player page to play audios based on the id that I will get in a future from the previous page…

I tried to do what you tell me but it continues to malfunction.
I’ll try to explain what’s going on:
When I enter into playerPage for first time, everything is fine. I can play / pause / stop the audio without problems.

I go back to the previous page. And when I return to the player page, everything seems to be fine too. But here the problems begin:

  • If I press the play button, it plays. If I press it again (to pause), it does nothing. If I press it again, it pauses the audio.
  • If I play back the audio and go back to the previous page, the audio stops, but it automatically plays again, even though it is on the page before the player page.

I do not understand how this can happen if I’m supposed to reset everything every time I enter the page.