I'm trying to create a Drum Kit website. I use array as a placeholder to all the sound files, and use loop to call the play() function.
When I try to load, the debug consol said: "Uncaught DOMException DOMException: Failed to load because no supported source was found."
The problem is that if I replace "audio.src = playlist[i];" by "audio.src = playlist[1];", the website can locate the source of the file & play the selected sound. But if I replace [1] by [i], the website can't locate the source file. So why is it?
Do you know why Javascript behaves this way? I can find another way to get the website to work but this thing has been tickling in my mind for a while.
Below is my Javascript codes:
var audio = new Audio();
var playlist = new Array("sounds/crash.mp3","sounds/kick-bass.mp3","sounds/snare.mp3","sounds/tom-1.mp3","sounds/tom-2.mp3","sounds/tom-3.mp3","sounds/tom-4.mp3");
var drum = document.querySelectorAll(".drum")
for (var i = 0; i < drum.length; i++) {
drum[i].addEventListener("click", play);
function play() {
audio.src = playlist[i];
audio.play();
}
}
Below is the HTML:
<body>
<h1 id="title">Drum đĽ Kit</h1>
<div class="set">
<button class="w drum">w</button>
<button class="a drum">a</button>
<button class="s drum">s</button>
<button class="d drum">d</button>
<button class="j drum">j</button>
<button class="k drum">k</button>
<button class="l drum">l</button>
</div>
<script src="index.js"></script>
</body>
Without the HTML it's difficult to say. But it seems like the number of items returned by document.querySelectorAll(".drum") is greater than the number of items in playlist. So eventually you run out of playlist items and audio.src is assigned the value undefined.
Related
I have an rate app box,
I want the user to rate the app from 1-5 by clicking one of five buttons.
The button that was clicked should have color, all the others none. So if he clicked first on 3 and then 2, when clicking on 2 the color from the 3 button will be removed so only the last button was clicked (in this case 2) will have a color.
I DID manage to do it using button array, but i know for sure there is shorter way that isnt involved button array, only by code inside the function.
html:
<body>
<div class="container">
<div class="img-container">
<img src="./images/icon-star.svg" alt="" class="img-star">
</div>
<div class="content">
<h1>How did we do?</h1>
<p id="content-paragraph">
Please let us know how we did with your support request. All feedback is appreciated
to help us improve our offering!
</p>
</div>
<div class="buttons-container">
<button value = 1 class="choose " id="btn-one" onclick="paintBtn(this)">1</button>
<button value = 2 class="choose" id="btn-two" onclick="paintBtn(this)">2</button>
<button value = 3 class="choose" id="btn-three" onclick="paintBtn(this)">3</button>
<button value = 4 class="choose" id="btn-four" onclick="paintBtn(this)">4</button>
<button value = 5 class="choose" id="btn-five" onclick="paintBtn(this)">5</button>
</div>
<form action="thankYou.html">
<button id="submit">SUBMIT</button>
</form>
<script src="index.js"></script>
</body
js:
const buttonOne = document.getElementById("btn-one")
const buttonTwo = document.getElementById("btn-two")
const buttonThree = document.getElementById("btn-three")
const buttonFour = document.getElementById("btn-four")
const buttonFive = document.getElementById("btn-five")
const buttonsArr = [buttonOne, buttonTwo, buttonThree, buttonFour, buttonFive]
function paintBtn(button) {
buttonsArr.map(btn => btn.classList.remove("btn-clicked"))
button.classList.add("btn-clicked")
}
The shorter way of doing and not having to pass every button inside an array would be to do a document.querySelectorAll(".choose") and with that way you would be able to access the NodeList of matching elements to your class.
You can examine it just like any array. If the array is empty (that is, its length property is 0), then no matches would be found.
Otherwise, you can use standard array notation to access the contents of the list. You can use any common looping statement, such as a forEach statement.
It works just fine as in the attached example.
function paintBtn(newClickedButton) {
// clear styling from buttons
let buttons = document.querySelectorAll(".choose");
buttons.forEach(function(button){
button.classList.remove("btn-clicked");
});
newClickedButton.classList.add("btn-clicked");
}
.btn-clicked{
background-color: red;
}
<link href="https://cdn.jsdelivr.net/npm/bootstrap#5.1.3/dist/css/bootstrap.min.css" rel="stylesheet"/>
<body>
<div class="container">
<div class="img-container">
<img src="./images/icon-star.svg" alt="" class="img-star">
</div>
<div class="content">
<h1>How did we do?</h1>
<p id="content-paragraph">
Please let us know how we did with your support request. All feedback is appreciated
to help us improve our offering!
</p>
</div>
<div class="buttons-container">
<button value = 1 class=" choose" id="btn-one" onclick="paintBtn(this)">1</button>
<button value = 2 class=" choose" id="btn-two" onclick="paintBtn(this)">2</button>
<button value = 3 class=" choose" id="btn-three" onclick="paintBtn(this)">3</button>
<button value = 4 class=" choose" id="btn-four" onclick="paintBtn(this)">4</button>
<button value = 5 class=" choose" id="btn-five" onclick="paintBtn(this)">5</button>
</div>
<form action="thankYou.html">
<button id="submit">SUBMIT</button>
</form>
<script src="index.js"></script>
</body>
use onclick functionallaity to solve this problem okay
You can use instead document.getElementsByClassName to search for the button that is currently clicked instead of searching and traversing through all of the buttons:
function paintBtn(newClickedButton) {
const clickedButtonClassName = "btn-clicked";
const clickedButton = document.getElementsByClassName(clickedButtonClassName)[0];
clickedButton.remove(clickedButtonClassName);
newClickedButton.classList.add(clickedButtonClassName);
}
Hello wizards of the internet!
Im new to javascript and finally found an efficient way to loop through ID's and toggle them. The code below adds the button id + "-box" text to show the result as 'display: flex'. If the ID is already visible it will set it to 'display: none'. For the future I need to add a lot of different smartphones to a website. I need an efficient way to only display 1 box at a time. I tried many different things but they all end in a huge document full of double code :(
(the style in html is to prevent the javascript double-click bug)
<!-- Smartphone Brands -->
<div id="brand-box" class="brand-container">
<button id="apple" class="brand" type="button" onclick="showBrand(this.id)">Apple</button>
<button id="samsung" class="brand" type="button" onclick="showBrand(this.id)">Samsung</button>
<button id="huawei" class="brand" type="button" onclick="showBrand(this.id)">Huawei</button>
</div>
<!-- Apple Smartphones -->
<div id="apple-box" class="block-container" style="display:none;">
<button id="apple1" class="block">iPhone 1</button>
<button id="apple2" class="block">iPhone 2</button>
<button id="apple3" class="block">iPhone 3</button>
</div>
<!-- Samsung Smartphones -->
<div id="samsung-box" class="block-container" style="display:none;">
<button id="samsung1" class="block">Samsung 1</button>
<button id="samsung2" class="block">Samsung 2</button>
<button id="samsung3" class="block">Samsung 3</button>
</div>
<!-- Huawei Smartphones -->
<div id="huawei-box" class="block-container" style="display:none;">
<button id="huawei1" class="block">Huawei 1</button>
<button id="huawei2" class="block">Huawei 2</button>
<button id="huawei3" class="block">Huawei 3</button>
</div>
function showBrand(clicked_id) {
var brand = document.getElementById(clicked_id+'-box');
if (brand.style.display == "none") {
brand.style.display = "flex";
}
else {
brand.style.display = "none";
}
}
One possible approach is modifying your function so that, when button is clicked, it...
memorizes the current visibility status of the target brand
hides all the brands
chooses a new value for the target brand depending on the old one
Like this:
function toggleBrand(clicked_id) {
var brand = document.getElementById(clicked_id+'-box');
var wasVisible = brand.style.display === 'flex';
var allBrands = document.querySelectorAll('[id$="-box"]');
allBrands.forEach(el => el.style.display = 'none');
brand.style.display = wasVisible ? 'none' : 'flex';
}
Now, while using attribute 'tail' selector is kinda neat, I'd recommend applying the same class or data attribute to all of those containers, and using according selector to collect them.
And yes, the renaming (showBrand => toggleBrand) was intentional: your original function actually toggles the brand, didn't show them. If you want instead to always show the brands on click, just drop that wasVisible check and always assign 'flex' as new value to brand.style.display.
This question already has answers here:
Why does jQuery or a DOM method such as getElementById not find the element?
(6 answers)
Closed 5 years ago.
DOM-structure in .html
Theres .js and bootstr containers for making stylish gallery.
<script src="main.js"></script>
<div class="container-fluid" id="gal">
<div class="row">
<div class="col-md-offset-2 col-md-8 col-sm-offset-1 col-sm-10 col-xs-12">
<div class="container-fluid galbody" id="gallery3">
<h2 id="galhead">Gallery</h2>
<div id="col1">
</div>
<div id="col2">
</div>
<div id="col3">
</div>
</div>
<div class="container-fluid galbody" id="gallery2">
<div id="col1">
</div>
<div id="col2">
</div>
</div>
<div class="container-fluid galbody" id="gallery1">
<div id="col1">
</div>
</div>
</div>
</div>
</div>
Im trying to insert within .js functions and methods images that are in array arr[] urls.
there is an main.js code:
document.write("hey!");
//definin' width of browser workspace
var galdiv3 = document.getElementById("gallery3").className = "none";
var galdiv2 = document.getElementById("gallery2").className = "none";
var galdiv1 = document.getElementById("gallery1").className = "none";
//creating array of future gallerydir images paths list
var arr = [];
//creating async flow for read json with paths. after calling back func for parse read text as array list in array (arr)
fs.readFile("gallist.json", function cb(err,rd){
var imgList = JSON.parse(rd);
imgList.forEach(function(file) {
arr += file + ", ";
}, this);
console.log(arr);
});
function singleGrid()
{
galdiv1.removeAttribute(className = " none");
function imgFill(){
for (var file in arr){
var x = document.createElement("div");
x.className();
}
}
imgFill();
}
singleGrid();
Problem is there :
var galdiv3 = document.getElementById("gallery3")**.className = "none"**;
var galdiv2 = document.getElementById("gallery2")**.className = "none"**;
var galdiv1 = document.getElementById("gallery1")**.className = "none"**;
Console throws err "Uncaught TypeError: Cannot set property 'className' of null"
you're trying to access DOM element before they've been inserted into the page.
so in the expression
var galdiv3 = document.getElementById("gallery3").className = "none";
the expression document.getElementById("gallery3") returns null. as consequence: null.className throws the error.
this happens because the <script></script> tag executes his content in the moment it's added to the page, that is, during the loading of the page, before the other tags are added. For this, when the script is executed, there are no other elements in the page so that you cannot find them.
move the <script src="main.js"></script> to the bottom or simply put all the code inside the window.onload event.
I'm building an app using AngularJS, and I'm using the soundcloud API to stream sounds through two different players.
My problem is that I want to have both the players to play sound simultaneously, which is not happening at the moment.
angular
.module('mtcApp')
.controller('PlayerCtrl', PlayerCtrl);
PlayerCtrl.$inject = ['$scope'];
function PlayerCtrl($scope){
$scope.startPlayerA = function(track){
const id = track.id;
console.log(id);
SC
.stream(`/tracks/${id}`)
.then(function(player){
$('#playA').on('click', function(){
player.play();
});
$('#pauseA').on('click', function(){
player.pause();
console.log(player);
});
});
};
$scope.startPlayerB = function(track){
const id = track.id;
console.log(id);
SC
.stream(`/tracks/${id}`)
.then(function(player){
$('#playB').on('click', function(){
player.play();
});
$('#pauseB').on('click', function(){
player.pause();
});
});
};
}
<script src="https://ajax.googleapis.com/ajax/libs/angularjs/1.2.23/angular.min.js"></script>
<script src="https://ajax.googleapis.com/ajax/libs/jquery/2.1.1/jquery.min.js"></script>
<div class="" ng-controller="MainCtrl">
<div class="">
<div class="">
<div ng-controller="PlayerCtrl as vm">
<div class="fl w-50 mv3 bg-grey">
<h3>Deck A</h3>
<button id="playA"> **PLAY** </button>
<button id="pauseA">**STOP**</button>
</div>
<div class="fl w-50 mv3 bg-grey">
<h3>Deck B</h3>
<button id="playB"> **PLAY** </button>
<button id="pauseB">**STOP**</button>
</div>
<sc-search></sc-search>
</div>
</div>
</div>
</div>
What is happening now is that if $scope.startPlayerA.player is playing and $(#playB) is clicked, $scope.startPlayerB.player starts playing but $scope.startPlayerA.player stops, anyone has an idea of how i can prevent this from happening?
thanks
<div class="Banner">
<div class="container">
<table><td>
<h1 id="overskrift">myhead</h1>
<p id="midtext">
fillertext
</p>
<p id="sluttekst">
morefiller
</p>
</td>
<td>
<img src="2.jpeg" id="billedSkift" height="200px"width="200px"></img>
</td>
</table></div>
</div>
<center>
<div class="container" >
<div class="btn-group btn-group-lg" role="toolbar">
<a class="btn btn-default" href="#" id="changetxt" role="group" >Kuvertering</a>
<a class="btn btn-default" href="#" id="printbrev" role="group" >Printbrevflet</a>
</div>
</div></center>
<script> $("#changetxt").on("click", function(){
var oeverskrift = 'the new headline';
var førstetext='the new text';
var andentext='some more new text';
document.getElementById('overskrift').innerHTML = oeverskrift;
document.getElementById('midtekst').innerHTML = førstetext;
document.getElementById('sluttekst').innerHTML = andentext;
});
</script>
I have used this method to change similar text in a testdocument however i seems to completely ignore the script here, i have tried several methods however none succesful even though the button is responsive.
ive run myself into a mindbogling corner any suggestions/help is greatly appreciated
1: You have a small typo:
document.getElementById('midtekst').innerHTML = førstetext; // typo 'midtekst' should be 'midtext'
2: Did you remember to embed jQuery above your JavaScript?
3: The ø in var førstetext='the new text'; breaks it on my local machine in Chrome but not in Safari. The fiddle works in both browsers. Try removing the ø.