ryanhagz ryanhagz - 2 months ago 7
Javascript Question

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');

});

Answer

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()});

});