Hello and thanks for looking up.
I have decided to learn Javascript by trial and error and Googling the stuff that I need. So far so good, but when I tried something a bit tricky, a slider, things got tough.
I dont really have good knowledge about syntax in Javascript and how expressions should be written in functions but I am trying.
So here we have a simple 4 images in a div with 2 arrows slider. When we click the arrow we want the counter to decrease by 1, we want to be sure it doesnt equal 0 and if it does we change it to 4, and when this is done we give the respective image ( img[counter] ) a z index of 50 for example. But it doesnt work. For some reason.
Here is a fiddle of the whole thing and hope I dont trouble you guys too much with this.
https://jsfiddle.net/wu2Lysrv/3/
function slideEngine() {
var img1 = document.querySelector("#img1");
var img2 = document.querySelector("#img2");
var img3 = document.querySelector("#img3");
var img4 = document.querySelector("#img4");
var counter = 1;
function slideL() {
counter--;
if (counter == 0) {
counter = 4;
}
img[counter].setAttribute("z-index", "50");
}
}
I would understand if someone goes aggro, since I bet this piece of code over there is very very wrong. Still I would like to learn how do I do it right.
The slideL function lives inside slideEngine, so your html doesn't have direct access to it.
One potential fix is to simply remove the wrapping function, since it doesn't seem to be used anywhere. However, there are other issues with the code that will prevent it from working. I've attempted to fix some below.
var img1 = document.querySelector("#img1");
var img2 = document.querySelector("#img2");
var img3 = document.querySelector("#img3");
var img4 = document.querySelector("#img4");
var counter = 1;
function slideL() {
counter--;
if (counter == 0) {
counter = 4;
}
window['img'+counter].style.zIndex = 50;
}
I didn't tes this, but try it out.
Related
I trying to make a small text based rpg game, but I came across array in js and then I came to problems, I failing to increase the index number by using i instead of 0 like myArray[i]
I made a jsfiddle so you guys can see what I mean.
jsfiddle
When you press the button til you get a warming, it should increase the i to 2, but it don't, but still comes with warming and increasing the attack variable.
This is your attackUp function:
function attackUp(){
var i = 0;
var attackCost = xpforlevel[i];
if (attackCost < attackxp) {
alert("WARMING!");
attack++;
document.getElementById('attack').innerHTML = attack;
i++;
document.getElementById('i').innerHTML = i;
}
}
Notice that your var i = 0 statement doesn't really make sense (because everytime attackUp is called, i will be reset to = 0 at the beginning). To fix that, erase this var i = 0 statement from your function and put in the beginning of your JS code:
var i = 0;
var attackxp = 0;
var attack = 1;
Further, your function will only update i if attackCost < attackxp, otherwise it will change nothing. You need to put the i++; statement outside your if-block, like this:
function attackUp(){
//erase this line: var i = 0;
var attackCost = xpforlevel[i];
i++; //added this line
if (attackCost < attackxp) {
alert("WARMING!");
attack++;
document.getElementById('attack').innerHTML = attack;
//erase this line: i++;
document.getElementById('i').innerHTML = i;
}
}
As your i is a local variable, it is initiated as 0 every time you call attackUp(). You should put it besides attackxp and attack.
For more information about the scope of variable in JavaScript, see w3schools or this question.
So I am a total JS novice, but I had someone write some code to be used within Qualtics survey. That code is now broken and I am trying to fix it up, there is an error with this line:
var timingObj=${e://Field/TimingObj};
I was hoping someone could help explain this line to me so I may be able to fix it up. (I have to full code, but that seemed a bit long to have someone go through.) I understand the first part is setting the variable named timingobj equal to something.
What that is is confusing to me, especially with the "//" which I understand to denote a note and not code. This code had worked in the past but now gives me an error. Any help understanding what I am working with would be amazing.
Thanks!
Update full code as provided to me:
//configurations
var bindInterval=10;
//initiate
var timingObj=${e://Field/TimingObj};
timingObj.version=3;
var startTiming=function(tag){
var currentTimeObj=timingObj[tag];
if (!currentTimeObj) {
currentTimeObj={};
currentTimeObj.startTimes=[];
currentTimeObj.elapseTimes=[];
currentTimeObj.totalElapsed=0;
timingObj[tag]=currentTimeObj;
}
var time=(new Date()).getTime();
currentTimeObj.startTimes.push(time);
currentTimeObj.startTime=time;
timingObj.activateTag=tag;
};
var closePopupCallback=function(){
//stop timing
var time=(new Date()).getTime();
var currentTag = timingObj.activateTag;
var currentTimeObj = timingObj[currentTag];
var elapsed=time - currentTimeObj.startTime;
currentTimeObj.elapseTimes.push(elapsed);
var totalElapsed=currentTimeObj.totalElapsed + elapsed;
currentTimeObj.totalElapsed=totalElapsed;
Qualtrics.SurveyEngine.setEmbeddedData(currentTag+'_Time',totalElapsed);
Qualtrics.SurveyEngine.setEmbeddedData(currentTag+'_Count',currentTimeObj.startTimes.length);
var timingObjSerialized=Object.toJSON(timingObj);
Qualtrics.SurveyEngine.setEmbeddedData('TimingObj',timingObjSerialized);
};
var bindCloseEvent=function() {
//window.document.observe('dom:loaded',func) and document.observe('dom:loaded',func) did not work
var closeButton=$('bottomNavClose');
if (closeButton) {
closeButton.observe('click', closePopupCallback);
} else{
setTimeout(bindCloseEvent,bindInterval);
}
};
// bad smell
var bindLightBoxCloseEvent=function(){
var lightBox=$('lightbox');
if (lightBox) {
lightBox.observe('click', closePopupCallback);
} else{
setTimeout(bindLightBoxCloseEvent,bindInterval);
}
};
bindLightBoxCloseEvent();
bindCloseEvent();
Qualtrics.SurveyEngine.addOnload(function(){
});
This should be an easy fix:
try:
var timingObj = "${e://Field/TimingObj}";
When using Qualtrics piped text in JavaScript, you must enclose the piped text in quotes.
If the piped text is a number that you plan on using and manipulating, as I am assuming, you should use parseInt() to ensure you don't have issues:
var timingObj = parseInt("${e://Field/TimingObj}");
Since the full code makes it clear that the item you are passing in is meant to be an object, I am assuming it is being passed in valid JSON, you should parse it as such:
var timingObj = JSON.parse("${e://Field/TimingObj}");
Okay, I hope you don't all facepalm when you see this - I'm still finding my way around javascript.
I am putting together an RSVP form for a wedding website.
I want the guests to be able to add their names to the RSVP form, but only have as many fields showing as required. To this end, after each name field, there is a link to click, which will, when clicked, show a name field for the next guest.
The code below works... but I am sure it can be tidier.
I have tried to insert a for() loop into the code in several different ways, I can see that the for() loop increments correctly to the last value - but when it does so, it leaves only the last addEventListener in place. I can only assume, that I should be using a different kind of loop - or a different approach entirely.
How should I tidy up the following?
<script>
function showNextGuest(i) {
document.getElementsByTagName(\'fieldset\')[i].style.display = \'block\';
}
function initiateShowNextGuest() {
document.getElementsByTagName('fieldset')[0].getElementsByTagName('a')[0].addEventListener('click',function(){showNextGuest(1);},false);
document.getElementsByTagName('fieldset')[1].getElementsByTagName('a')[0].addEventListener('click',function(){showNextGuest(2);},false);
document.getElementsByTagName('fieldset')[2].getElementsByTagName('a')[0].addEventListener('click',function(){showNextGuest(3);},false);
document.getElementsByTagName('fieldset')[3].getElementsByTagName('a')[0].addEventListener('click',function(){showNextGuest(4);},false);
document.getElementsByTagName('fieldset')[4].getElementsByTagName('a')[0].addEventListener('click',function(){showNextGuest(5);},false);
}
window.onload = initiateShowNextGuest();
</script>
Your intuition is right - a for loop could indeed simplify it and so could a query selector:
var fieldsSet = document.querySelectorAll("fieldset"); // get all the field sets
var fieldss = [].slice.call(asSet); // convert the html selection to a JS array.
fields.map(function(field){
return field.querySelector("a"); // get the first link for the field
}).forEach(function(link, i){
// bind the event with the right index.
link.addEventListener("click", showNextGuest.bind(null, i+1), false);
});
This can be shortened to:
var links = document.querySelectorAll("fieldset a:first-of-type");
[].forEach.call(links, function(link, i){
link.addEventListener("click", showNextGuest.bind(null, i+1), false);
});
function nextGuest () {
for(var i = 0; i < 5; i++){
document.getElementsByTagName('fieldset')[i]
.getElementsByTagName('a')[0]
.addEventListener('click',function(){
showNextGuest(parseInt(i + 1));
}, false);
}
}
Benjamin's answer above is the best given, so I have accepted it.
Nevertheless, for the sake of completeness, I wanted to show the (simpler, if less elegant) solution I used in the end, so that future readers can compare and contrast between the code in the question and the code below:
<script>
var initiateShowNextGuest = [];
function showNextGuest(j) {
document.getElementsByTagName('fieldset')[j].style.display = 'block';
}
function initiateShowNextGuestFunction(i) {
return function() {
var j = i + 1;
document.getElementsByTagName('fieldset')[i].getElementsByTagName('a')[0].addEventListener('click',function(){showNextGuest(j);},false);
};
}
function initiateShowNextGuests() {
for (var i = 0; i < 5; i++) {
initiateShowNextGuest[i] = initiateShowNextGuestFunction(i);
initiateShowNextGuest[i]();
}
}
window.onload = initiateShowNextGuests();
</script>
In summary, the function initiateShowNextGuests() loops through (and then executes) initiateShowNextGuestFunction(i) 5 times, setting up the 5 anonymous functions which are manually written out in the code in the original question, while avoiding the closure-loop problem.
var checkduplicates = new Array();
drawOne(i);
//console.log(checkduplicates)
function drawOne(i)
{
//randomly select one photo
var picinfo = photos[Math.floor(Math.random()*photos.length)];
//check duplicates pic, if duplicates exist, get another one
while(checkduplicates.indexOf(picinfo)!=-1||picinfo.title.length>10)
{
picinfo = photos[Math.floor(Math.random()*photos.length)];
}
checkduplicates.push(picinfo);
var ctx = document.getElementsByClassName("canvas")[i].getContext('2d');
var img = new Image();
//get the pic URL
img.src = "http://farm" + picinfo.farm + ".static.flickr.com/"
+ picinfo.server + "/" + picinfo.id + "_" + picinfo.secret + "_m.jpg";
img.onload = function()
{
// Draw pieces
ctx.drawImage(img,0,0,132,150);
ctx.drawImage(frame,0,0,133,152);
if(picinfo.title=="")
$("#"+i).append("Untitled");
else
$("#"+i).append(picinfo.title);
i++;
if (i != canvaslength)
{
drawOne(i);
}
}
What I am doing here is that I am dynamically generate pictures to fill out 16 canvas and some people said that I am using asynchronous recursion which I dont even notice. I have tried to use loop instead of recursion but somehow ended it up getting exception that i dont know how to fix. So I stick to recursion. However, my problem is that how I can detect the end of the recursion like the commented line shows there is only one item in the array.
//console.log(checkduplicates)
and the explanation I got is that as I understand, the commented console.log is executed before a bunch of recursion of drawOne function finished But what I wanted was that I wanted the full 16 images to be fully loaded and then select them so that I can do something with them. Therefore, the question is how I can detect the end of the recursion. Thank you. You are welcomed to ignore most of my codes and just look at the recursion part.
This is not 'asynchronous recursion'. That would imply that at least two of these loops are running at the same time, and they return asynchronously. Which is simply not the case.
Basically the only time you STOP recursion is when i == canvaslength.
So, just take that if statement.
if (i != canvaslength)
{
drawOne(i);
}else{
console.log('recursion is done') // do what you want here.
}
I am creating a simple game with HTML, CSS, and JavaScript (jQuery). There is main ship, where all of the particles (bullets) originate from. They are each just divs. Then, enemy divs are places randomly throughout the screen.
I am looking for an efficient way to test if each particle is hitting a particular enemy. I have something that starts to work out fine, but gets bogged down incredibly fast. I am new to js, so my code is pretty messy and probably inefficient in many other ways. Any suggestions would be greatly appreciated!
Here is my section that creates enemies and tests for hitting:
var createEnemy = function(){
var xRandom = Math.floor(Math.random() * (containerW-50));
var yRandom = Math.floor(Math.random() * (containerH-50));
var newEnemy = $('<div class="enemy"></div>');
$(newEnemy).css({'left':xRandom,'top':yRandom}).appendTo('#container').fadeTo(200, .7);
var hitTest = setInterval(function(){
var enemy = $(newEnemy);
var particle = $('.particle');
var enemyT = enemy.offset().top;
var enemyB = enemy.height()+enemyT;
var enemyL = enemy.offset().left;
var enemyR = enemy.width()+enemyL;
var particleT = particle.offset().top;
var particleB = particle.height();
var particleL = particle.offset().left;
var particleR = particle.width();
if(particleT >= enemyT-particleB && particleT <= enemyB && particleL >= enemyL-particleR && particleL <= enemyR){
enemy.hide();
var removeEnemy = setTimeout(function(){
newEnemy.remove();
clearInterval(hitTest, 0);
},500);
}
}, 20);
}
var enemyInt = setInterval(createEnemy, 1000);
Is getting something like this to run smoothly in a browser realistic? Does my code just need some changes? You will probably need more context so:
EDIT 1/12/2012: Game Link Removed // Not Relevant
NOTE: This works best in Chrome and Safari at the moment.
EDIT 3/22/2011: Changed enemy fadeOut() to hide() so that you can see exactly when an enemy disappears (it is sometimes delayed). The hitTest only seems to trigger when you click on the actual enemy, so if it passes through, it is not being triggered.Also, I forgot to clearInterval on hitTest. This seemed to boost performance dramatically, but still isn't quite there.
If you want the best performance, drop jQuery and use native JavaScript.
If that isn't an option, profile the slowest parts and use native DOM there, e.g.
var newEnemy = $('<div class="enemy"></div>');
...becomes...
var newEnemy = document.createElement('div');
newEnemy.className = 'enemy';