0

I am a rails newbie and I just want to extract a rails object and attribute (@tracks.audio) using javascript. I want to apply audio files dynamically from the db instead of using the hard coded version seen on commented lines 1,2,3

Here is the tracks.js.erb

    // Event listener for DOM
document.addEventListener("DOMContentLoaded", theDOMHasLoaded, false);

// array of audio files (stored in a folder called music)
var files = ["<% @tracks.audio %>" , // this code doesn't work!
      "chooseyourweapon.mp3", // 1
      "interlude.mp3", // 2
      "scriptures.mp3" // 3
      ];

///////////////////////////////////////////////
// Find and store audio info
///////////////////////////////////////////////

// array for AudioObjects
var audioList = [];
// components and the index for their AudioObject
var componentDict = {};
// store AudioObject that is currently playing
var playingAudio = null;
// store playhead id if one is being dragged
var onplayhead = null;

/* AudioObject Constructor */
function AudioObject(audio, duration) {
  this.audio = audio;
  this.id = audio.id;
  this.duration = duration;
}
/* bindAudioPlayer
 * Store audioplayer components in correct AudioObject
 * num identifes correct audioplayer
 */
AudioObject.prototype.bindAudioPlayer = function (num) {
  this.audioplayer = document.getElementById("audioplayer-" + num);
  this.playbutton = document.getElementById("playbutton-" + num);
  this.timeline = document.getElementById("timeline-" + num);
  this.playhead = document.getElementById("playhead-" + num);
  this.timelineWidth = this.timeline.offsetWidth - this.playhead.offsetWidth
}

/* addEventListeners() */
AudioObject.prototype.addEventListeners = function () {
  this.audio.addEventListener("timeupdate", AudioObject.prototype.timeUpdate, false);
  this.audio.addEventListener("durationchange", AudioObject.prototype.durationChange, false);
  this.timeline.addEventListener("click", AudioObject.prototype.timelineClick, false);
  this.playbutton.addEventListener("click", AudioObject.prototype.pressPlay, false);
  // Makes playhead draggable 
  this.playhead.addEventListener('mousedown', AudioObject.prototype.mouseDown, false);
  window.addEventListener('mouseup', mouseUp, false);
}

/* populateAudioList */
function populateAudioList() {
  var audioElements = document.getElementsByClassName("audio");
  for (i = 0; i < audioElements.length; i++) {
    audioList.push(
      new AudioObject(audioElements[i], 0)
    );
    audioList[i].bindAudioPlayer(i);
    audioList[i].addEventListeners();
  }
}

/* populateComponentDictionary() 
 * {key=element id : value=index of audioList} */
function populateComponentDictionary() {
  for (i = 0; i < audioList.length; i++) {
    componentDict[audioList[i].audio.id] = i;
    componentDict[audioList[i].playbutton.id] = i;
    componentDict[audioList[i].timeline.id] = i;
    componentDict[audioList[i].playhead.id] = i;
  }
}

///////////////////////////////////////////////
// Update Audio Player
///////////////////////////////////////////////

/* durationChange
 * set duration for AudioObject */
AudioObject.prototype.durationChange = function () {
  var ao = audioList[getAudioListIndex(this.id)];
  ao.duration = this.duration;
}

/* pressPlay() 
 * call play() for correct AudioObject
 */
AudioObject.prototype.pressPlay = function () {
  var index = getAudioListIndex(this.id);
  audioList[index].play();
}

/* play() 
 * play or pause selected audio, if there is a song playing pause it
 */
AudioObject.prototype.play = function () {
  if (this == playingAudio) {
    playingAudio = null;
    this.audio.pause();
    changeClass(this.playbutton, "playbutton play");
  }
  // else check if playing audio exists and pause it, then start this
  else {
    if (playingAudio != null) {
      playingAudio.audio.pause();
      changeClass(playingAudio.playbutton, "playbutton play");
    }
    this.audio.play();
    playingAudio = this;
    changeClass(this.playbutton, "playbutton pause");
  }
}

/* timelineClick()
 * get timeline's AudioObject
 */
AudioObject.prototype.timelineClick = function (event) {
  var ao = audioList[getAudioListIndex(this.id)];
  ao.audio.currentTime = ao.audio.duration * clickPercent(event, ao.timeline, ao.timelineWidth);
}

/* mouseDown */
AudioObject.prototype.mouseDown = function (event) {
  onplayhead = this.id;
  var ao = audioList[getAudioListIndex(this.id)];
  window.addEventListener('mousemove', AudioObject.prototype.moveplayhead, true);
  ao.audio.removeEventListener('timeupdate', AudioObject.prototype.timeUpdate, false);
}

/* mouseUp EventListener
 * getting input from all mouse clicks */
function mouseUp(e) {
  if (onplayhead != null) {
    var ao = audioList[getAudioListIndex(onplayhead)];
    window.removeEventListener('mousemove', AudioObject.prototype.moveplayhead, true);
    // change current time
    ao.audio.currentTime = ao.audio.duration * clickPercent(e, ao.timeline, ao.timelineWidth);
    ao.audio.addEventListener('timeupdate', AudioObject.prototype.timeUpdate, false);
  }
  onplayhead = null;
}

/* mousemove EventListener
 * Moves playhead as user drags */
AudioObject.prototype.moveplayhead = function (e) {
  var ao = audioList[getAudioListIndex(onplayhead)];
  var newMargLeft = e.pageX - ao.timeline.offsetLeft;
  if (newMargLeft >= 0 && newMargLeft <= ao.timelineWidth) {
    document.getElementById(onplayhead).style.marginLeft = newMargLeft + "px";
  }
  if (newMargLeft < 0) {
    playhead.style.marginLeft = "0px";
  }
  if (newMargLeft > ao.timelineWidth) {
    playhead.style.marginLeft = ao.timelineWidth + "px";
  }
}

/* timeUpdate 
 * Synchronizes playhead position with current point in audio 
 * this is the html audio element
 */
AudioObject.prototype.timeUpdate = function () {
  // audio element's AudioObject
  var ao = audioList[getAudioListIndex(this.id)];
  var playPercent = ao.timelineWidth * (ao.audio.currentTime / ao.duration);
  ao.playhead.style.marginLeft = playPercent + "px";
  // If song is over
  if (ao.audio.currentTime == ao.duration) {
    changeClass(ao.playbutton, "playbutton play");
    ao.audio.currentTime = 0;
    ao.audio.pause();
    playingAudio = null;
  }
}

///////////////////////////////////////////////
// Utility Methods
///////////////////////////////////////////////

/* changeClass 
 * overwrites element's class names */
function changeClass(element, newClasses) {
  element.className = newClasses;
}

/* getAudioListIndex
 * Given an element's id, find the index in audioList for the correct AudioObject */
function getAudioListIndex(id) {
  return componentDict[id];
}

/* clickPercent()
 * returns click as decimal (.77) of the total timelineWidth */
function clickPercent(e, timeline, timelineWidth) {
  return (e.pageX - timeline.offsetLeft) / timelineWidth;
}

///////////////////////////////////////////////
// GENERATE HTML FOR AUDIO ELEMENTS AND PLAYERS
///////////////////////////////////////////////

/* createAudioElements
 * create audio elements for each file in files */
function createAudioElements() {
  for (f in files) {
    var audioString = "<audio id=\"audio-" + f + "\" class=\"audio\" preload=\"true\"><source src=\"http://www.alexkatz.me/codepen/music/" + files[f] + "\"></audio>";
    $("#audio-players").append(audioString);
  }
}

/* createAudioPlayers
 * create audio players for each file in files */
function createAudioPlayers() {
  for (f in files) {
    var playerString = "<div id=\"audioplayer-" + f + "\" class=\"audioplayer\"><button id=\"playbutton-" + f + "\" class=\"play playbutton\"></button><div id=\"timeline-" + f + "\" class=\"timeline\"><div id=\"playhead-" + f + "\" class=\"playhead\"></div></div></div>";
    $("#audio-players").append(playerString);
  }
}

/* theDOMHasLoaded()
 * Execute when DOM is loaded */
function theDOMHasLoaded(e) {
  // Generate HTML for audio elements and audio players
  createAudioElements();
  createAudioPlayers();

  // Populate Audio List
  populateAudioList();
  populateComponentDictionary();
}
2
  • Well, normally you would just use a controller which sends the file? Or use it as an asset? I'm not entirely sure what your problem or source of confusion is? I don't know what you expect <% @tracks.audio %> to do? Show a file URL? Commented Mar 9, 2016 at 4:20
  • the javascript code above creates an audio player. I do not believe <% @tracks.audio %> does anything actually because I don't expect javascript to interpret ruby, but i know there must be a way for javascript to get what i have stored in the db and display it on the index page like so,( example link codepen.io/katzkode/pen/ZbxYYG ) , i just don't know how to do that yet. Commented Mar 9, 2016 at 4:33

3 Answers 3

2

You can always use the 'gon' gem. Found here: https://github.com/gazay/gon. With this you are able to pass your rails variables to your JS.

Gemfile

gem 'gon'

application.html.erb

<head>    
  <%= include gon %>
</head>

your_controller.rb

class YourController < ApplicationController
  def index
    # Define your variable and now you can pass it in JS
    @variable = YourModel.all
    gon.new_variable = @variable
  end
end

Now 'gon.new_variable' is available in your JS file.

Sign up to request clarification or add additional context in comments.

1 Comment

Thanks, going to try it asap!
0

There are many ways to do this. Usually we use:

var variable_a = '<%= my_fav_variable %>'

or

var variable_b = '<%= raw %>'

Comments

0

There are many ways to do this:

  • Setting window variables
  • Passing data attributes to an object
  • The Gon gem (mentioned in another answer)
  • Making a JSON endpoint and calling it from Javascript (basically an API).

Some of the solutions I mentioned are explained in this video:

http://railscasts.com/episodes/324-passing-data-to-javascript

Watch it and choose the option that suits your needs, keep in mind there are also other ways to do this that I didn't mention.

1 Comment

Thanks, I watched the video and decided to go with the gon implementation. So far so good.

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.