feel free to launch abuse at me if I have missed a question that expains this. I'm pretty new to JS aswell.
I'm building a timtable for shuttle buses to and from our offices. I wanted to add a new location.
My current code is this:
function changeTimes (selectedOption) {
var myTT = document.getElementById("timeTable");
var myLocs = document.getElementById("Locations");
if (selectedOption=='1') {
myTT.innerHTML = brdepStr;
myLocs.innerHTML = 'Bath Road';
} else {
myTT.innerHTML = badepStr;
myLocs.innerHTML = 'Buckingham Avenue';
I then changed it to the following, which didn't work. Being a complete newbie to JS I'm guessing you can't have two "else" statements in a row?
function changeTimes (selectedOption) {
var myTT = document.getElementById("timeTable");
var myLocs = document.getElementById("Locations");
if (selectedOption=='1') {
myTT.innerHTML = brdepStr;
myLocs.innerHTML = 'Bath Road';
} else {
myTT.innerHTML = badepStr;
myLocs.innerHTML = 'Buckingham Avenue';
} else {
myTT.innerHTML = bwdepStr;
myLocs.innerHTML = 'Brunel Way' ;
}
Really appreciate any help. Thanks.
As #Mkilmanas said, there can be no 2 else on the same if block (else will always be executed if all previous if/else if statements are not executed, so if you need 2 elses, you can just cut the code from the second else into the first else). Change the first else to else if(selectedOption == '2') and you should be okay for this part :)
Related
I want to be able to change the value of a global variable when it is being used by a function as a parameter.
My javascript:
function playAudio(audioFile, canPlay) {
if (canPlay < 2 && audioFile.paused) {
canPlay = canPlay + 1;
audioFile.play();
} else {
if (canPlay >= 2) {
alert("This audio has already been played twice.");
} else {
alert("Please wait for the audio to finish playing.");
};
};
};
const btnPitch01 = document.getElementById("btnPitch01");
const audioFilePitch01 = new Audio("../aud/Pitch01.wav");
var canPlayPitch01 = 0;
btnPitch01.addEventListener("click", function() {
playAudio(audioFilePitch01, canPlayPitch01);
});
My HTML:
<body>
<button id="btnPitch01">Play Pitch01</button>
<button id="btnPitch02">Play Pitch02</button>
<script src="js/js-master.js"></script>
</body>
My scenario:
I'm building a Musical Aptitude Test for personal use that won't be hosted online. There are going to be hundreds of buttons each corresponding to their own audio files. Each audio file may only be played twice and no more than that. Buttons may not be pressed while their corresponding audio files are already playing.
All of that was working completely fine, until I optimised the function to use parameters. I know this would be good to avoid copy-pasting the same function hundreds of times, but it has broken the solution I used to prevent the audio from being played more than once. The "canPlayPitch01" variable, when it is being used as a parameter, no longer gets incremented, and therefore makes the [if (canPlay < 2)] useless.
How would I go about solving this? Even if it is bad coding practise, I would prefer to keep using the method I'm currently using, because I think it is a very logical one.
I'm a beginner and know very little, so please forgive any mistakes or poor coding practises. I welcome corrections and tips.
Thank you very much!
It's not possible, since variables are passed by value, not by reference. You should return the new value, and the caller should assign it to the variable.
function playAudio(audioFile, canPlay) {
if (canPlay < 2 && audioFile.paused) {
canPlay = canPlay + 1;
audioFile.play();
} else {
if (canPlay >= 2) {
alert("This audio has already been played twice.");
} else {
alert("Please wait for the audio to finish playing.");
};
};
return canPlay;
};
const btnPitch01 = document.getElementById("btnPitch01");
const audioFilePitch01 = new Audio("../aud/Pitch01.wav");
var canPlayPitch01 = 0;
btnPitch01.addEventListener("click", function() {
canPlayPitch01 = playAudio(audioFilePitch01, canPlayPitch01);
});
A little improvement of the data will fix the stated problem and probably have quite a few side benefits elsewhere in the code.
Your data looks like this:
const btnPitch01 = document.getElementById("btnPitch01");
const audioFilePitch01 = new Audio("../aud/Pitch01.wav");
var canPlayPitch01 = 0;
// and, judging by the naming used, there's probably more like this:
const btnPitch02 = document.getElementById("btnPitch02");
const audioFilePitch02 = new Audio("../aud/Pitch02.wav");
var canPlayPitch02 = 0;
// and so on
Now consider that global data looking like this:
const model = {
btnPitch01: {
canPlay: 0,
el: document.getElementById("btnPitch01"),
audioFile: new Audio("../aud/Pitch01.wav")
},
btnPitch02: { /* and so on */ }
}
Your event listener(s) can say:
btnPitch01.addEventListener("click", function(event) {
// notice how (if this is all that's done here) we can shrink this even further later
playAudio(event);
});
And your playAudio function can have a side-effect on the data:
function playAudio(event) {
// here's how we get from the button to the model item
const item = model[event.target.id];
if (item.canPlay < 2 && item.audioFile.paused) {
item.canPlay++;
item.audioFile.play();
} else {
if (item.canPlay >= 2) {
alert("This audio has already been played twice.");
} else {
alert("Please wait for the audio to finish playing.");
};
};
};
Side note: the model can probably be built in code...
// you can automate this even more using String padStart() on 1,2,3...
const baseIds = [ '01', '02', ... ];
const model = Object.fromEntries(
baseIds.map(baseId => {
const id = `btnPitch${baseId}`;
const value = {
canPlay: 0,
el: document.getElementById(id),
audioFile: new Audio(`../aud/Pitch${baseId}.wav`)
}
return [id, value];
})
);
// you can build the event listeners in a loop, too
// (or in the loop above)
Object.values(model).forEach(value => {
value.el.addEventListener("click", playAudio)
})
below is an example of the function.
btnPitch01.addEventListener("click", function() {
if ( this.dataset.numberOfPlays >= this.dataset.allowedNumberOfPlays ) return;
playAudio(audioFilePitch01, canPlayPitch01);
this.dataset.numberOfPlays++;
});
you would want to select all of your buttons and assign this to them after your html is loaded.
https://developer.mozilla.org/en-US/docs/Web/API/Document/getElementsByClassName
const listOfButtons = document.getElementsByClassName('pitchButton');
listOfButtons.forEach( item => {
item.addEventListener("click", () => {
if ( this.dataset.numberOfPlays >= this.dataset.allowedNumberOfPlays ) return;
playAudio("audioFilePitch" + this.id);
this.dataset.numberOfPlays++;
});
I have this example code
var randFriend = friendList[Math.floor(Math.random() * friendList.length)];
if (randFriend == admin) {
//Here
}
else if (randFriend != admin) {
client.removeFriend(randFriend);
}
How can I do if if randfriend == admin to do again var randFriend = friendList[Math.floor(Math.random() * friendList.length)]; and check if(randFriend == admin) again. In other words, to restart that again.
I think that it's done with return, but I don't know. Thanks
I wouldn't use recursion or loops with random conditions, because you will have problems to estimate the runtime, and if the use case changes and you would have more elements you want to ignore, then the probability to find the correct element will decrease.
A better idea would be to filter the array to remove the elements you want to ignore and then pick a random element from that list.
var nonAdminList = friendList.filter(person => person != admin);
if( nonAdminList.length === 0 ) {
throw new Error('no non admin persons available');
}
client.removeFriend(nonAdminList[Math.floor(Math.random() * nonAdminList.length)]);
If I'm understanding the question correctly, you could use a while loop to keep randomizing until an admin isn't selected
var friendAdmin = true;
var randFriend;
while(friendAdmin){
randFriend = friendList[Math.floor(Math.random() * friendList.length)];
if(randFriend != admin) friendAdmin = false;
}
client.removeFriend(randFriend);
I would put your code into a function so that you can invoke the function again if you want to repeat it. For example:
function choose(){
var randFriend = friendList[Math.floor(Math.random() * friendList.length)];
if(randFriend == admin){
choose(); //this repeats the choose function, which will run the random friend code again
}
else if(randFriend != admin){
client.removeFriend(randFriend);
return; //this exits the function
}
}
I'm trying to make a page out of javascript. I'm pretty new to all this, so bear with me.
I have a form, and when you press submit I have the following bit to see if the fields are left blank:
function calculatePrice()
{
var GasPrice = document.getElementById("number1").value;
var Distance = document.getElementById("number2").value;
var Mileage = document.getElementById("number3").value;
var norepeat = false;
if (norepeat==false && (GasPrice =="" || Distance =="" || Mileage ==""))
{
var para=document.createElement("p");
para.setAttribute("class", "error");
var node=document.createTextNode("All fields must be completed");
para.appendChild(node);
var element=document.getElementById("content");
element.appendChild(para);
var norepeat = true;
}
I created the error as a paragraph tag that appears. The problem is that when I press submit more than once, it writes the error message every time. I tried the norepeat variable thing, but it doesn't seem to be working. Any help?
Though I'm not completely sure your intentions, it'd have to look something more like:
var norepeat = false;
function calculatePrice() {
if(!norepeat && (/* other conditions here */)) {
norepeat = true;
}
return !(/* other conditions above */);
}
Where norepeat is defined in a global scope. Also, remember to use === as opposed to ==. And trimming the string before testing it wouldn't be a horrible idea...
But, wouldn't you want the errors to still persist if the user hasn't corrected them - isn't that the point of validation?
I think what you are trying to do is this. This assumes you add a new div "myError" that holds your error message. You'll also need to consider not submitting the form too if validation doesn't pass.
function calculatePrice() {
var GasPrice = document.getElementById("number1").value;
var Distance = document.getElementById("number2").value;
var Mileage = document.getElementById("number3").value;
var error = document.getElementById("myError");
if (GasPrice == "" || Distance == "" || Mileage == "") {
error.style.display = "block";
return false;
}
else {
error.style.display = "none";
return true;
}
}
I was trying to show a text gradually on the screen (like marquee). e.g. H.. He.. Hell.. Hello. when I'm tracing it in debug in VS2010 it's working! but when it's actually running it shows the whole sentence at once.
I made a certain "delay" for about 3 seconds between each letter so it would suppose to take a while, but in reality it's shows everything immediately.
Who's the genius to solve this mystery? (please don't give me advices how to create the marquee effect, it's not the issue anymore. now it's just a WAR between me and javascript!) I'm assuming that it has to do with synchronization when calling function from function?
Thanks to whomever will help me get my sanity back.
you can download the code from here (VS project):
http://pcgroup.co.il/downloads/misc/function_from_function.zip
or view it here:
<body>
<script type="text/javascript">
//trying to display this source sentence letter by letter:
var source = "hi javascript why are you being such a pain";
var target = "";
var pos = 0;
var mayGoOn = false;
//this function calls another function which suppose to "build" the sentence increasing index using the global var pos (it's even working when following it in debug)
function textticker() {
if (pos < source.length) {
flash();
if (mayGoOn == true) {
pos++;
mayGoOn = false;
document.write(target);
textticker();
}
}
}
function flash() {
//I tried to put returns everywhere assuming that this may solve it probably one of them in not necessary but it doesn't solve it
if (mayGoOn == true) { return; }
while (true) {
var d = new Date();
if (d.getSeconds() % 3 == 0) {
//alert('this suppose to happen only in about every 3 seconds');
target = source.substring(0, pos);
mayGoOn = true;
return;
}
}
}
textticker();
</script>
You're obviously doing it wrong. Take a look at this.
var message = "Hello World!";
function print(msg, idx) {
if(!idx) {
idx = 0;
}
$('#hello').html(msg.substring(0, idx));
if(idx < msg.length) {
setTimeout(function() { print(msg, idx + 1) }, 200);
}
}
print(message);
Demo: http://jsbin.com/evehus
Alone, this code works:
CustomButton = {
1: function () {
alert("Just testing")
},
}
I add the code below and the code above stops working:
function getvisitingnow() {
return document.location;
}
function getcontents(uri) {
var req = new XMLHttpRequest();
req.open('GET', uri, true);
req.onreadystatechange = function (aEvt) {
if (req.readyState == 4) {
if(req.status == 200) {
return req.responseText;
}
}
};
req.send();
}
function regexforsitefound(uri, searchcontents) {
var re = new RegExp("\\<div class=g\\>.*?(?:\\<a href=\\\"?(.*?)\\\"?\\>.*?){2}\\</div\\>", "mi");
var sitefound = searchcontents.match(re);
if (sitefound[0]) return sitefound[0] else return null;
}
function regexforcategoryfound(uri, searchcontents) {
var re = new RegExp("\\<div class=g\\>.*?(?:\\<a href=\\\"?(.*?)\\\"?\\>.*?){2}\\</div\\>", "mi");
var categoryfound = searchcontents.match(re);
if (categoryfound[1]) return categoryfound[1] else return null;
}
function regexfordomainname(uri) {
var re = new RegExp("http://(?:[A-Za-z0-9-]+\\.)?[A-Za-z0-9-]+\\.[A-Za-z0-9-]+/?", "si");
var domainname = uri.match(re);
if (domainname) return domainname;
}
function regexforparentdir(uri) {
var re = new RegExp("http://(?:[A-Za-z0-9-]+\\.)?[A-Za-z0-9-]+\\.[A-Za-z0-9-]+/?", "si");
var parentdir = uri.match(re);
if (parentdir) return parentdir;
}
function getcomparisonlink(visitingnow) {
var searchuri = null;
var searchcontents = null;
var uri = visitingnow;
while(true) {
searchuri = 'http://www.google.com.br/search?';
searchuri += 'q='+ uri +'&btnG=Search+Directory&hl=en&cat=gwd%2FTop';
searchcontents = getcontents(searchuri);
var sitefound = regexforsitefound(searchcontents);
if (sitefound) {
var categoryfound = regexforcategoryfound(searchcontents);
if (categoryfound) {
return categoryfound;
}
} else {
var domainname = regexfordomainname(uri);
if (!domainname) {
var parentdir = regexforparentdir(uri);
uri = parentdir;
} else {
return null;
}
}
}
}
function clickedlink(event){
var visitingnow = getvisitingnow();
if (visitingnow) {
getcomparisonlink(visitingnow);
if (comparisonlink) {
tab.open(comparisonlink);
};
}
}
function createBookmarkItem() {
const XUL_NS = "http://www.mozilla.org/keymaster/gatekeeper/there.is.only.xul";
var item = document.createElementNS(XUL_NS, "toolbarbutton");
item.setAttribute("id", "Testing-Doit-Button2");
item.setAttribute("class", "bookmark-item pagerank");
item.setAttribute("tooltiptext", "Do it!");
item.setAttribute("oncommand", "testing_doit();");
return item;
}
function placeBookmarkItem() {
var toolbar = document.getElementById("PersonalToolbar");
var button = createBookmarkItem();
toolbar.appendChild(button);
}
Why?
try adding your functions one by one. see at which function your code stops working. then empty the function contents only to put it back with pieces at a time. check again where your code stops working. about there should be a syntax error.
But as Bobby suggests, the easier way is to try Firefox Errorlog, or maybe Firebug.
One little JavaScript-error can break a lot of things. You have forgotten to add semicolons in two places.
There needs to be a semicolon after sitefound[0] here:
function regexforsitefound(uri, searchcontents) {
var re = new RegExp("\\<div class=g\\>.*?(?:\\<a href=\\\"?(.*?)\\\"?\\>.*? ){2}\\</div\\>", "mi");
var sitefound = searchcontents.match(re);
if (sitefound[0]) return sitefound[0] else return null;
}
and one after categoryfound[1] here:
function regexforcategoryfound(uri, searchcontents) {
var re = new RegExp("\\<div class=g\\>.*?(?:\\<a href=\\\"?(.*?)\\\"?\\>.*?){2}\\</div\\>", "mi");
var categoryfound = searchcontents.match(re);
if (categoryfound[1]) return categoryfound[1] else return null;
}
if (sitefound[0]) return sitefound[0] else return null;
This syntax is invalid.
Try:
if (sitefound[0])
return sitefound[0];
else
return null;
If you are a Mac user, open (a recent version) of Safari and hit
⌥⌘ + i,
which opens up a great panel with lots of charts and data about the client-server interaction. You can also see and locate javascript errors, or debug javascript in a console directly. neat.
For Firefox, try the excellent firebug to see, what went wrong where .. in their own words: [with Firebug] .. you can edit, debug, and monitor CSS, HTML, and JavaScript live in any web page.
The comma after the function in CustomButton can break code the code in IE. Also, if you are using CustomButton the first time here, you should introduce it with var. I know these are not the issues you asked for, but otherwise, everything seems correct.