Search code examples
javascriptjqueryhtmlhtml5-canvasweb-audio-api

How can I call javascript library functions externally?


I'm working on an app that deals with web audio and waveform display.

For it, I'm using a library called Wavesurfer made for specifically that.

The problem I'm running into is calling the function for the track to play. I tried putting it into a external JavaScript script using jQuery's .click(), but it didn't work.

So, I decided to try the onclick() event on the button itself like this:

<div style="text-align: center">
  <button class="btn btn-primary" onclick="wavesurfer.playPause()">
    Play
  </button>
</div>

and the only change is that it tells me in the console, "wavesurfer is not defined.", but it HAS to be defined since it's still drawing the waveform of the audio!

The strangest part is this EXACT code works fine in CodePen!

EDIT: Full code below:

<!DOCTYPE html>
<html>
<head>
<script src="https://cdnjs.cloudflare.com/ajax/libs/wavesurfer.js/1.1.2/wavesurfer.min.js"></script>
<script src="https://ajax.googleapis.com/ajax/libs/jquery/3.1.0/jquery.min.js"></script>
<script src="C:\Users\Ryan\Desktop\wavesurfer.js"></script>
</head>
<body>
<div id="waveform"></div>

<div style="text-align: center">
  <button class="btn btn-primary" onclick="wavesurfer.playPause()">
Play
  </button>
</div>
</body>
</html>

And JavaScript:

$(document).ready(function(){
var wavesurfer = WaveSurfer.create({
    container: '#waveform',
    waveColor: 'red',
    progressColor: 'purple'
});
wavesurfer.load('https://archive.org/download/Metallica_37/Metallica-MasterOfPuppets.mp3');

});

Solution

  • Variable Scope

    The problem you are having is one of scope.

    What is Scope

    All variables in javascript have a scope. A variable can not be access if it is out of scope. For variables declared with the var token their scope is to the function they are declared in. Variables declared outside any function has a global scope. Global scope means that the variable can be access from anywhere on the page.

    Example

    var myGlobal = 10; // this is outside any function and is global
    function myFunction(){
        var myFuncLoc = 20;  // this is inside the function and scoped to the function
        console.log(myFuncLoc); // >> 20  // is in scope can be displayed
        console.log(myGlobal); // >> 10  // is in scope can be displayed
        function(){
            var myFuncLoc1 = 30;
            console.log(myFuncLoc); // >> 20  // is in scope can be displayed
            console.log(myFuncLoc1); // >> 30  // is in scope can be displayed
            console.log(myGlobal); // >> 10  // is in scope can be displayed
        }
        console.log(myFuncLoc); // >> 20  // is in scope can be displayed
        console.log(myGlobal); // >> 10  // is in scope can be displayed
        // next is out of scope
        console.log(myFuncLoc1); // Throws ReferenceError: myFuncLoc1 is not defined
    }
    console.log(myGlobal); // >> 10  // is in scope can be displayed
        // next is out of scope
    console.log(myFuncLoc); // Throws ReferenceError: myFuncLoc is not defined
    console.log(myFuncLoc1); // Throws ReferenceError: myFuncLoc1 is not defined
    

    That is a brief overview and there is also the block scoped variable declarations with the tokens let and const A block is everything inside { } You should read up on scope as that is an important concept for almost all programing languages.

    What is wrong

    So your problem is you have a variable that is out of scope.

    $(document).ready(function(){
        // wavesurfer is scoped to this function only
        // and can not be seen in the global scope.
        var wavesurfer = WaveSurfer.create({
            container: '#waveform',
            waveColor: 'red',
            progressColor: 'purple'
        });
        wavesurfer.load('https://archive.org/download/Metallica_37/Metallica-MasterOfPuppets.mp3');
    
    });
    

    The onclick is in the global scope and can not see the variable that has been declared in function scope.

    <!-- can not see wavesurfer -->
    <button class="btn btn-primary" onclick="wavesurfer.playPause()">
    

    The hack fix.

    To fix you can ensure wavesurfer is global

    // outside any function
    var wavesurfer; // declares wavesurfer as a globally scoped variable
    
    $(document).ready(function(){
        // wavesurfer is global
        // so do not use the var token be cause if you do then you create a second
        // variable called wavesurfer inside this function
        wavesurfer = WaveSurfer.create({  
            container: '#waveform',
            waveColor: 'red',
            progressColor: 'purple'
        });
        wavesurfer.load('https://archive.org/download/Metallica_37/Metallica-MasterOfPuppets.mp3');
    
    });
    

    That will fix your problem

    The prefered fix

    A better solution is to add the onclick event where the wavesurfer has scope and this avoids polluting the global scope.

    Change the button

    <!-- remove the onclick from the play button and give it an id-->
    <button class="btn btn-primary" id='playButton'>
    

    And then the code

    $(document).ready(function(){
        // function scope wavesurfer
        var wavesurfer = WaveSurfer.create({  
            container: '#waveform',
            waveColor: 'red',
            progressColor: 'purple'
        });
    
        wavesurfer.load('https://archive.org/download/Metallica_37/Metallica-MasterOfPuppets.mp3');
    
        // use only one of the following code lines
    
        // add the click event where wavesurfer has scope.
        playButton.addEventListener("click",function(){wavesurfer.playPause()});
    
        // for the purists :P
        document.getElementById("playButton").addEventListener("click", function(){wavesurfer.playPause()});
    
    });