Pregunta

I'm creating a music-based app that uses Knockout for it's bindings. All of the tracks listed in the app are pulled externally from Soundcloud like so:

$.getJSON('http://api.soundcloud.com/users/guy-j/tracks.json?client_id=c4bc3b1a93902abecbaca3fa4582d970', {limit: 200}, function(data) {
            vm.tracks($.map(data, function (track) {
                return {
                    artwork: track.artwork_url,
                    avatar: track.user.avatar_url,
                    date: track.created_at,
                    description: track.description,
                    duration: track.duration,
                    listens: track.playback_count,
                    permalink: track.permalink_url,
                    purhcase: track.purchase_url,
                    stream: track.stream_url,
                    track: track.title
                };
            }));
        });

These tracks (once fetched) are pushed into a blank observableArray and the HTML view is then bound to that array and generates a list of tracks. I've got the audio playing/pausing like so:

To select/play a track, each <li> that's generated from the observableArray has a click handler called 'goToTrack' which then passes an observable called 'self.chosenTrackData' the selected track and my audio element is then bound with 'chosenTrackData' to play the chosen track.

My problem now lies with the fact that I'm not quite sure what the best way to approach the next/prev track features using Knockout would be. I'd have to some how distinguish the current point in the observableArray and then ++ or -- depending which option you've selected?

Any help would be greatly appreciated as I'm still learning Knockout!

¿Fue útil?

Solución

I'd suggest keeping an internal "current track" number that you increment or decrement and base a computed on that.

function PlayerViewModel() {
    var self = this,
        currentTrackNo = ko.observable(0);

    // data
    self.tracks = ko.observableArray();

    // computeds
    self.currentTrack = ko.computed(function () {
        return self.tracks()[currentTrackNo()];
    });
    self.hasTrack = function (track) {
        return !!self.currentTrack();
    };
    self.hasNextTrack = ko.computed(function () {
        return currentTrackNo() < self.tracks().length - 1;
    });
    self.hasPrevTrack = ko.computed(function () {
        return currentTrackNo() > 0;
    });

    // API
    self.setNextTrack = function () {
        if (self.hasNextTrack()) {
            currentTrackNo(currentTrackNo() + 1);
        }
    };
    self.setPrevTrack = function () {
        if (self.hasPrevTrack()) {
            currentTrackNo(currentTrackNo() - 1);
        }
    };
    self.setTrack = function (track) {
        var trackNo = ko.utils.arrayIndexOf(self.tracks(), track);
        currentTrackNo(trackNo);
    };

    // init
    $.getJSON('...', {limit: 200}); etc;
}

Bind your "current track" view component to the currentTrack observable. Make sure that you use hasTrack in some way (as currentTrack might be undefined).


Alternative implementation, avoiding the maintenance of a separate track number:

function PlayerViewModel() {
    var self = this;

    // data
    self.tracks = ko.observableArray();
    self.currentTrack = ko.observable();

    // computeds
    self.currentTrackNo = ko.computed(function () {
        var currentTrack = self.currentTrack();
        return ko.utils.arrayIndexOf(self.tracks(), currentTrack);
    });
    self.hasTrack = function (track) {
        return !!self.currentTrack();
    };
    self.hasNextTrack = ko.computed(function () {
        return self.currentTrackNo() < self.tracks().length - 1;
    });
    self.hasPrevTrack = ko.computed(function () {
        return self.currentTrackNo() > 0;
    });

    // API
    self.setNextTrack = function () {
        if (self.hasNextTrack()) {
            self.currentTrack(self.tracks()[self.currentTrackNo() + 1]);
        }
    };
    self.setPrevTrack = function () {
        if (self.hasPrevTrack()) {
            self.currentTrack(self.tracks()[self.currentTrackNo() - 1]);
        }
    };
    self.setTrack = function (track) {
        // make sure that track is actually in self.tracks here
        self.currentTrack(track);
    };

    // init
    $.getJSON('...', {limit: 200}); etc;
}
Licenciado bajo: CC-BY-SA con atribución
No afiliado a StackOverflow
scroll top