Search code examples
javascripthtmlwindowsaudiowinjs

getFileAsync is too slow, causes appendChild to append to last div in an array


I have a grid of buttons in my Javascript Windows app using WinJS.

    <div class="padtable">
        <button class="pad" id="pad11">Empty</button>
        <button class="pad" id="pad12">Empty</button>
        <button class="pad" id="pad13">Empty</button>
        <button class="pad" id="pad14">Empty</button><br />
        <button class="pad" id="pad21">Empty</button>
        <button class="pad" id="pad22">Empty</button>
        <button class="pad" id="pad23">Empty</button>
        <button class="pad" id="pad24">Empty</button><br />
        <button class="pad" id="pad31">Empty</button>
        <button class="pad" id="pad32">Empty</button>
        <button class="pad" id="pad33">Empty</button>
        <button class="pad" id="pad34">Empty</button><br />
        <button class="pad" id="pad41">Empty</button>
        <button class="pad" id="pad42">Empty</button>
        <button class="pad" id="pad43">Empty</button>
        <button class="pad" id="pad44">Empty</button><br />
    </div>

Then I try to cycle through all the buttons, and if it is associated with a file, I try to get the file as an audio tag, and append it to it. Except that getting the file takes too long, so instead of appending the audio tag to each individual button, it appends all audio tags to the last button. How can I work around this? Here is the code that does the appending:

var pads = document.querySelectorAll(".pad");
            // Cycle through all pads, attaching audio tags where mappings exist
            for (var padCount = 0; padCount < pads.length - 1; padCount++) {
                // Find out if the mapping exists
                var fileMappingExists = false;
                if (fileMappings[pads[padCount].id] != null) {
                    fileMappingExists = true;
                }

                // If the file mapping exists, get the file from the FAL, and create audio tags tied to their respective buttons
                if (fileMappingExists) {
                    Windows.Storage.AccessCache.StorageApplicationPermissions.futureAccessList.getFileAsync(fileMappings[pads[padCount].id].audioFile).done(function (audioFile) {
                        if (audioFile) {
                            var audioId = "audioPlayer_" + pads[padCount].id;
                            var audioPlayer = document.createElement('audio');
                            audioPlayer.setAttribute("id", audioId);
                            audioPlayer.setAttribute("controls", "true");
                            audioPlayer.setAttribute("style", "display:none;");
                            audioPlayer.setAttribute("msAudioCategory", "SoundEffects");
                            audioPlayer.src = URL.createObjectURL(audioFile, { oneTimeOnly: true });
                            document.getElementById(pads[padCount].id).appendChild(audioPlayer);
                            audioPlayer.load();

                            // Assign button click to song play
                            // TODO | BUG: Click events and audio tags are only assigned to last pad because of getFileAsync
                            var pad = document.getElementById(pads[padCount].id);
                            pad.addEventListener("click", function () {
                                // Set audio to start if it's already playing
                                if (audioPlayer.currentTime != 0)
                                    audioPlayer.currentTime = 0;

                                // Play the file
                                audioPlayer.play();
                            }, false);

                            WinJS.log && WinJS.log("Audio file was added successfully for" + pads[padCount].id, "sample", "status");
                        }
                        else {
                            document.getElementById("output").innerText += "\nAudio file not found for " + pads[padCount];
                        }
                    });


         }
}

Solution

  • To understand what is going on here read this

    Here's one way of approaching a fix:

    // If the file mapping exists, get the file from the FAL, and create audio tags tied to their respective buttons
    if (fileMappingExists) {
        Windows.Storage.AccessCache.StorageApplicationPermissions.futureAccessList.getFileAsync(fileMappings[pads[padCount].id].audioFile).done(
            (function (pc) {
                return function (audioFile) {
                    if (audioFile) {
                        var audioId = "audioPlayer_" + pads[pc].id;
                        var audioPlayer = document.createElement('audio');
                        audioPlayer.setAttribute("id", audioId);
                        audioPlayer.setAttribute("controls", "true");
                        audioPlayer.setAttribute("style", "display:none;");
                        audioPlayer.setAttribute("msAudioCategory", "SoundEffects");
                        audioPlayer.src = URL.createObjectURL(audioFile, { oneTimeOnly: true });
                        document.getElementById(pads[pc].id).appendChild(audioPlayer);
                        audioPlayer.load();
    
                        // Assign button click to song play
                        // TODO | BUG: Click events and audio tags are only assigned to last pad because of getFileAsync
                        // FIXED AS WELL
                        var pad = document.getElementById(pads[pc].id);
                        pad.addEventListener("click", (function (ap) {
                            return function () {
                                // Set audio to start if it's already playing
                                if (ap.currentTime != 0)
                                    ap.currentTime = 0;
    
                                // Play the file
                                ap.play();
                            };
                        })(audioPlayer), false);
    
                        WinJS.log && WinJS.log("Audio file was added successfully for" + pads[pc].id, "sample", "status");
                    }
                    else {
                        document.getElementById("output").innerText += "\nAudio file not found for " + pads[pc];
                    }
                };
            })(padCount);
        );
    }