0

So, I'm making an audio player and I've got a bit of code to get the audio duration of the selected file, for the timer. It was working really well with Session, but then, as I might want more than one player per page, I decided to switch to ReactiveVar or ReactiveDict and I don't think I quite grasped how they work, because my code broke. Can you help me? What am I doing wrong?

This is the code as it was with Session.

Template.audioplayer.onRendered(
  function() {
    audio = $("audio").get(0);
  }
);

Template.audioplayer.helpers({
  audioduration: function() {
    if (!Session.get("audioduration")) {
      audioLenght = Meteor.setInterval(function() {
        var totaltime = parseInt(audio.duration, 10);
        var mins = Math.floor(audio.duration / 60, 10);
        var secs = totaltime - mins * 60;
        var gimmethetime = mins + ':' + (secs > 9 ? secs : '0' + secs);

        Session.set("audioduration", gimmethetime);
        return Session.get("audioduration");

      }, 500);
    } else {
      Meteor.clearInterval(audioLenght);
      return Session.get("audioduration");
    }
  }

});

This is my latest attempt at the same result with ReactiveVar. It came out with "TypeError: Cannot read property 'get' of undefined".

Template.audioplayer.onCreated(
  function() {
    audio = $("audio").get(0);

    this.audioduration = new ReactiveVar();

  }
);

Template.audioplayer.helpers({
  audioduration: function() {
    if (!Template.audioduration.get()) {
      audioLenght = Meteor.setInterval(function() {
        var totaltime = parseInt(audio.duration, 10);
        var mins = Math.floor(audio.duration / 60, 10);
        var secs = totaltime - mins * 60;
        var gimmethetime = mins + ':' + (secs > 9 ? secs : '0' + secs);

        Template.instance().audioduration.set(gimmethetime);
        return gimmethetime;

      }, 500);
    } else {
      Meteor.clearInterval(audioLenght);
      return Template.instance().audioduration.get();
    }
  }

});

Thanks in advance!

RPresle
  • 2,436
  • 3
  • 24
  • 28

1 Answers1

0

I would add some information before answering your question. I have seen a lot of resources over the Internet using the Session variable to store temporary data and this stunned me a little. You must understand that the Session lifecycle start when you load the page and ends when you reload the page or close your browser. Let's say you store all your temporary data inside the session, if I take time to got through all the application then my session will be polute with data from all these pages. You are not faulty I just wanted to add some information on this. Anyone correct me if I'm wrong.

Now comes the place to answer.

In your helper, you have a test. In this test you try to access the reactiveVar with Template.audioduration. But as you have made for all the other calls it should be Template.instance().audioduration.get()

Template.audioplayer.onCreated(
  function() {
    audio = $("audio").get(0);

    this.audioduration = new ReactiveVar();

  }
);

Template.audioplayer.helpers({
  audioduration: function() {
    if (!Template.instance().audioduration.get()) {
      audioLenght = Meteor.setInterval(function() {
        var totaltime = parseInt(audio.duration, 10);
        var mins = Math.floor(audio.duration / 60, 10);
        var secs = totaltime - mins * 60;
        var gimmethetime = mins + ':' + (secs > 9 ? secs : '0' + secs);

        Template.instance().audioduration.set(gimmethetime);
        return gimmethetime;

      }, 500);
    } else {
      Meteor.clearInterval(audioLenght);
      return Template.instance().audioduration.get();
    }
  }
});

Like this it should work...

EDIT :

You had a second error, I put it here for later reference and explanation.

"Exception in setInterval callback: TypeError: Cannot read property 'audioduration' of null". In order to correct it, I told you to create a variable in the helper scope with Template.instance().

This is a typical JS error. In JS, all the diffulty is to understand what is the scope of a function. In this case, it is possible to access the Template variable in the helper but it cannot be accessed inside the callback. If you reference the template instance inside the context of the helper then it can be accessed from the callback. I don't know much about how are linked the different contexts in this particular case. But it is quite usual that the this object cannot be accessed by callbacks, we are forced to user var that = this;. `See this post.

Community
  • 1
  • 1
RPresle
  • 2,436
  • 3
  • 24
  • 28
  • Thanks, RPresle, but unfornately it consoled "Exception in setInterval callback: TypeError: Cannot read property 'audioduration' of null". I tried moving the setInterval function to the onCreated or onRendered section, but so far it either returned me that or "TypeError: Cannot read property 'duration' of undefined". That was a problem I wasn't having with Session (as my check tended to prevent it), so I am a little lost, here. – Cristina Jadi Martins Nov 17 '16 at 06:06
  • This may come from the scope of the Templace.instance(). Can you try to create a variable `var instance = Template.instance();` and call `instance.audioduration:set(...)` instead of `Templace.instance()...` – RPresle Nov 17 '16 at 14:43
  • It worked! Weirdly enough if I make the instance variable helper scoped it already solves the problem, is it supposed to do that? If I try to make it local scoped but don't define it inside the helper first, however, it returns an error. Sorry for my inexperience and thank you for all your patience. – Cristina Jadi Martins Nov 17 '16 at 16:10
  • No need to apologize. JS contexts are not easy. See my edited answer – RPresle Nov 17 '16 at 18:31