for (var n = 0; n < 10; n++) {
$('#content-scroll' + n).mousewheel(function(event, delta) {
if (delta > 0) sliderUp(n - 1);
else if (delta < 0) sliderDown(n - 1);
return false; // prevent default
});
n++;
}
I have a problem with this code, variable "n" is not passed right to the mouswheel function which will add mousewheel only to number 9 (last number) and not to all 10 elements.
Can anyone explain how to pass a variable to this function so that it stays?
My take on this using a fully jQuery solution.
$("[id^='content-scroll']").mousewheel( function(event,delta) {
var n = this.id.replace(/content-scroll/,'');
if (delta > 0)
sliderUp(n);
else if (delta < 0)
sliderDown(n);
event.preventDefault();
});
EDIT: Actually, I may even try to figure out a way to pass the actual matching control to the slider* functions, but not knowing what they actually do I have no idea how or if that would work.
I believe this is an issue of closures in javascript, the n is actually a reference to the outside n variable. I believe the following should work instead:
for(var n=0;n<10;n++)
{
var localN = n;
$('#content-scroll'+n).mousewheel(function(event, delta) {
if (delta > 0) sliderUp(localN-1);
else if (delta < 0) sliderDown(localN-1);
return false; // prevent default
});
//is this really needed??
//n++;
}
This is asked a lot on SO (case in point). You need a closure to "trap" the value of n in each iteration:
for(var n=0;n<10;n++)
{
(function(n){
$('#content-scroll'+n).mousewheel(function(event, delta) {
if (delta > 0) sliderUp(n-1);
else if (delta < 0) sliderDown(n-1);
return false; // prevent default
});
})(n);
}
Are your n values supposed to go from 0-9 or 1-10?
If it's 0-9, change all n-1 expressions to just n.
If it's 1-10, change the for loop to var n=1,n<=10;n++, and all n-1 references to just n.
Also, remove the n++ on the bottom because your for loop already increments the value of n.
The reason that the code doesn't work is because the n variable is not evaluated during the loop.
You are creating an anonymous function in the loop that you pass to the mousewheel function, so the code in the anonymous function isn't executed until the mouse wheel even occurs. By then the value of the n variable is 10, or perhaps something completely different if you are using the variable anywhere else in the code.
If you instead use the Function function to create the function from a string, you can inject the current value of the n variable into the code:
for(var n=0; n<10; n++) {
$('#content-scroll' + n).mousewheel(
Function('event', 'delta',
'if (delta > 0) sliderUp(' + (n-1) + ');' +
'else if (delta < 0) sliderDown(' + (n-1) + ');' +
'return false; // prevent default'
)
);
}
However, should it be (n-1)? Should the mousewheel event for the content-scroll0 element call sliderup(-1)?
JQuery specifically allows the passing of event data, which may, or may not, be of use to you in this case:
for(var n=0;n<10;n++)
{
$('#content-scroll'+n).bind('mousewheel', {index:n}, function(event, delta) {
var innerN = event.data.index;
if (delta > 0) sliderUp(innerN-1);
else if (delta < 0) sliderDown(innerN-1);
return false; // prevent default
});
}
Related
I'm still pretty new to JavaScript and need to be pointed in the right direction on a tiny project that is just for practice.
Very sorry if I'm not posting incorrectly, this is my first post on Stack Overflow and any help is appreciated.
I've tried accomplishing my goal a few different ways and haven't gotten there.
attack.addEventListener("click", function(){
hit();
});
function hit(){
if (bossHealth.textContent > 0 && playerFocus.textContent >=2) {
playerFocus.textContent -= 2;
bossHealth.textContent -= 3;
console.log("attack");
}
else if (bossHealth.textContent >= 0 && playerFocus.textContent < 2){
alert("Attack costs 2 focus, try regenerating this turn to gain focus and health!");
}
};
strong.addEventListener("click", function(){
bigHit();
});
function bigHit(){
if(bossHealth.textContent > 0 && playerFocus.textContent >= 5){
playerFocus.textContent -= 6;
bossHealth.textContent -= 6;
console.log("strong attack");
}
else if (playerFocus <5){
alert("Strong attack costs 5 focus, if you do not have enough focus try regenerating for a turn");
}
else (bossHealth.textContent <= 0){
bossHealth.textContent = "Dead";
alert("You've killed the bad guy and saved the world!!!");
}
};
easy.addEventListener("click", function(){
reset();
});
function reset(){
playerHealth.textContent = 10;
playerFocus.textContent = 10;
bossHealth.textContent = 10;
};
hard.addEventListener("click", function(){
hardMode();
});
function hardMode(){
playerHealth.textContent = 10;
playerFocus.textContent = 10;
bossHealth.textContent = 15;
};
With function hit I don't get the alert in my else if statement
with function bigHit I also don't get my alert for the else if statement and neither part of the else statement works.
also subtraction works in my functions, but when trying to add another function that uses addition in the same way it adds the number to the end of the string instead of performing math
You really shouldn't depend on what is in the DOM for logic. You should try with local variables then update the DOM based on those variables.
var boss = {}
var player = {}
function reset(){
player.health = 10;
player.focus = 10;
boss.health = 10;
update()
};
function hit(){
if (boss.health > 0 && player.focus >=2) {
player.focus -= 2;
boss.health -= 3;
console.log("attack");
} else if (boss.health > 0 && player.focus < 2){
alert("Attack costs 2 focus, try regenerating this turn to gain focus and health!");
}
update()
}
function update() {
playerFocus.textContent = player.focus
playerHealth.textContent = player.health
bossHealth.textContent = boss.health
}
Your issue is caused by textContent automatically turning your numbers into strings, by managing the data using your own variables this doesn't affect your code's logic.
Alternatively you could parse the strings as numbers using new Number(playerFocus.textContent), parseFloat(playerFocus.textContent), or +playerFocus.textContent but your code will become very hard to read very quickly.
Hope this enough to help you to make more edits to your code.
It looks like your playerFocus variable is a DOM node? Based on that assumption, your condition is missing a check for its textContent:
if (bossHealth.textContent > 0 && playerFocus.textContent >= 5){
// ...
}
else if (playerFocus.textContent <5){
// ...
In JavaScript, else blocks cannot have conditions, so if you want to conditionally check whether bossHealth.textContent <= 0 at the end of your bigHit function, you will need to change it to an else if (bossHealth.textContent <= 0) { ... } block instead.
I'm adding on to #LoganMurphy's comment and my own. In order to use the value of bossHealth it needs to be an integer. Change your code to look something like this:
function hit(){
if (parseInt(bossHealth.textContent) > 0 && parseInt(playerFocus.textContent) >=2) {
playerFocus.textContent -= 2;
bossHealth.textContent -= 3;
console.log("attack");
}
else if (parseInt(bossHealth.textContent) >= 0 && parseInt(playerFocus.textContent) < 2){
alert("Attack costs 2 focus, try regenerating this turn to gain focus and health!");
}
};
https://www.w3schools.com/jsref/jsref_parseint.asp
I'm attempting to write a read only values in a html input using jQuery, and I've run into a problem where a single if statement fires twice.
Basically the input starts with a default value in the html [this is the readonly value]:
<input id="main-field" type="text" value="dan" >
Then, a jQuery 'keypress keydown' function checks the index of the pressed key in relation to the readonly word and if the index is before or after the word it returns 'true' which will add the characters, otherwise it will return false which will prevent adding chars. The problem is that if I type before the word it increases the index of the readonly word twice, where it should be increased by one (since the readonly word has moved by one index for each char).
Here's the 'keypress keydown' function; hopefully it's easy to understand (let me know if not, I want to get better at that as well):
var readOnlyEnd = $('#main-field').val().length,
readOnlyStart = 1;
$('#main-field').on('keypress keydown', function(event) {
var character = String.fromCharCode(event.keyCode).toLowerCase();
// note: using the jquery caret plugin
var pos = $('#main-field').caret();
// handling new character between 'a' and 'z' and the delete char.
if (((character >= 'a') && (character <= 'z')) || (event.which == 8)) {
// if delete is pressed:
if (event.which == 8) {
if (pos == readOnlyEnd) return false;
else if (pos < readOnlyStart) {
if (pos == 0) return true;
if (pos > 0) {
console.log('reudce index!!');
// Will reduce indexes.
readOnlyStart -= 1;
readOnlyEnd -= 1;
return true; // Will delete.
}
}
else if ((pos >= readOnlyStart) && (pos < readOnlyEnd)) return false;
}
// within the word.
else if ((pos >= readOnlyStart) && (pos < readOnlyEnd)) return false;
// before the readonly word. - HERE IS THE PROBLEM, INCREASING TWICE.
else if (pos < readOnlyStart) {
readOnlyStart += 1;
readOnlyEnd += 1;
return true; // Will add character
}
else {
return true;
}
}
else {
// In case something that doesn't affect the input was pressed (like left/right arrows).
return true;
}
});
Note: I'm using the jQuery caret plugin for the cursor place.
Please let me know if you have any ideas or suggestions, or if the solution to my problem is similar to a solution to another problem on here
You should use only one event. Either keypress or keydown in following statement:
$('#main-field').on('keypress keydown', function(event) {
This will fire event twice on a single key press.
So, change your statement to:
$('#main-field').on('keypress', function(event) {
I'm trying to create javascript that will count from 1 to 1000 and push any multiples of 3, 5 into an array called multiples then print that array out using console.log(). For some reason my code isn't working. Does anyone know why?
var n;
var multiples = [];
for(n = 1; n <= 1000; n += 1) {
console.log("Counting");
}
if(n % 3 === 0) {
n.push(multiples);
}
else {
}
if(n % 5 === 0) {
n.push(multiples);
}
else {
}
if(n >= 1000) {
console.log(multiples);
}
else {
}
There are few issues with your code. Using {} in your for block designates the scope of the code executing in each iteration. So in order to access each value for n you need to be placing your conditional statements inside of the {} and not outside of them.
There is a slight syntax error with your multiples array. In order to push a value into an array you would use the arrayname followed by the dot operator and then the push function with the argument being the value pushed. In terms of multiples and n, this means multiples.push(n).
When using an if() block, else is not required.
It is generally best practice to include the variable declaration inside of for loops, and also to use ++ as opposed to += 1.
Overall, your code would need to look more like this
var multiples = [];
console.log("Counting");
for(var n = 1; n <= 1000; n++) {
if(n % 3 === 0) {
multiples.push(n);
}
if(n % 5 === 0) {
multiples.push(n);
}
}
console.log(multiples);
I am creating one page site and then trying to get offsetTop on window.scroll, by which i want to traverse the DOM according to the slide.
a lot of tries.. feeling dumb now..
if anyone can help, would be highly appreciable.
thanks
here is the code and fiddle URL:
$(window).scroll(function () {
var y = $(window).scrollTop(),
a = $('#first').offset().top - 200,
b = $('#second').offset().top - 200,
c = $('#third').offset().top - 200,
d = $('#fourth').offset().top - 200;
if (y > a) {
$('h1').html('This is First Slide');
}
if (y > b) {
$('h1').html('This is Second Slide');
}
if (y > c) {
$('h1').html('This is Third Slide');
}
if (y > d) {
$('h1').html('This is Third Slide');
}
else{
$('h1').html('No heading');
}
});
http://jsfiddle.net/A8Hmr/9/
Your logic is correct it's just a miss with the ifs.
I will show the code and explain:
var a = $('#first').offset().top - 200,
b = $('#second').offset().top - 200,
c = $('#third').offset().top - 200,
d = $('#fourth').offset().top - 200;
$(window).scroll(function () {
var y = $(window).scrollTop();
if (y > a && y < b) {
$('h1').text('This is First Slide');
}
else if (y > b && y < c) {
$('h1').text('This is Second Slide');
}
else if (y > c && y < d) {
$('h1').text('This is Third Slide');
}
else if (y > d) {
$('h1').text('This is Third Slide');
}
else{
$('h1').text('No heading');
}
});
Demo
1) You don't need to take the offset of the slides on every scroll, since they don't change, you can put them outside of the scroll event, that way it will improve the performance.
2) The problem in the code was the if. Since they were all ifs (and not if/else if) statements, all of theme were checked if they were true. Meaning that if the first one was true the next one will not be true and it will enter in the else statement automaticaly overwriting the if that was true.
So you have to make them if/else if and since once y > a become true it will always be true (untill it goes to y < a) you must have an additional condition if y < b meaning if y is less then the next slide. Ofcourse once again you can use only if/else but what is the point in checking 5 things if only one is correct ? Performance should be a main thing in every js code. ;)
Version 2:
(function(){
var a = $('#first').offset().top - 200,
b = $('#second').offset().top - 200,
c = $('#third').offset().top - 200,
d = $('#fourth').offset().top - 200,
h1 = $('h1'),
textChange = ['No heading','This is First Slide','This is Second Slide','This is Third Slide', 'This is Third Slide']
$(window).scroll(function () {
var y = $(window).scrollTop();
if (y > a && y < b && h1.text() != textChange[1]) {
h1.text(textChange[1]);
}
else if (y > b && y < c && h1.text() != textChange[2]) {
h1.text(textChange[2]);
}
else if (y > c && y < d && h1.text() != textChange[3]) {
h1.text(textChange[3]);
}
else if (y > d && h1.text() != textChange[4]) {
h1.text(textChange[4]);
}
else if(y <= a && h1.text() != textChange[0]){
h1.text(textChange[0]);
}
});
})();
Demo
What change here?
1) I wrapped the whole thing in self invoking anonymous function (since it's not a good practice to have global variables).
2) We made a variable outside the scroll event that will hold the h1 so we don't have to go in the dom on every scroll event.
3) We made an array that will hold the text that will change. (and updated the values in the text scroll)
4) We changed the if condition in the if statement to check if the text is already the same so we don't have to change it again. So now it will fire only once instead of firing every time we scroll.
5) We changed the else to else if since it would enter once the text is the same an jump to the else.
Pretty much that should increase the performance a lot.
Have the function DashInsert(num) insert dashes ('-') between each two odd numbers in num. For example: if num is 454793 the output should be 4547-9-3. Don't count zero as an odd number.
Here is my code (not working). When I run it, I get the same response as an infinite loop where I have to kill the page but I can't see why. I know there are ways to do this by keeping it as a string but now I'm wondering why my way isn't working. Thanks...
function DashInsert(num) {
num = num.split("");
for (i = 1; i < num.length; i++) {
if (num[i - 1] % 2 != 0 && num[i] % 2 != 0) {
num.splice(i, 0, "-");
}
}
num = num.join("");
return num;
}
Using num.splice you are inserting new entries into the array, therefor increasing its length – and that makes the value of i “running behind” the increasing length of the array, so the break condition is never met.
And apart from that, on the next iteration after inserting a -, num[i-1] will be that - character, and therefor you are practically trying to check if '-' % 2 != 0 … that makes little sense as well.
So, when you insert a - into the array, you have to increase i by one as well – that will a) account for the length of the array having increased by one, and also it will check the next digit after the - on the next iteration:
function DashInsert(num) {
num = num.split("");
for (i = 1; i < num.length; i++) {
if (num[i - 1] % 2 != 0 && num[i] % 2 != 0) {
num.splice(i, 0, "-");
i++; // <- this is the IMPORTANT part!
}
}
num = num.join("");
return num;
}
alert(DashInsert("454793"));
http://jsfiddle.net/37wA9/
Once you insert a dash -, the if statement is checking this '-'%2 != 0 which is always true and thus inserts another dash, ad infinitum.
Here's one way to do it with replace using a regex and function:
function DashInsert(n) {
var f = function(m,i,s) { return m&s[i+1]&1 ? m+'-' : m; };
return String(n).replace(/\d/g,f);
}
DashInsert(454793) // "4547-9-3"
When you are adding a dash, this dash will be processed as a number on the next iteration. You need to forward one step.
function DashInsert(num) {
var num = num.split("");
for (var i = 1; i < num.length; i++) {
if ((num[i - 1] % 2 != 0) && (num[i] % 2 != 0)) {
num.splice(i, 0, "-");
i++; // This is the only thing that needs changing
}
}
num = num.join("");
return num;
}
It's because there are cases when you use the % operator on dash '-' itself, e.g. right after you splice a dash into the array.
You can correct this behavior by using a clone array.
function DashInsert(num) {
num = num.split("");
var clone = num.slice(0);
var offset = 0;
for (i = 1; i < num.length; i++) {
if (num[i - 1] % 2 != 0 && num[i] % 2 != 0) {
clone.splice(i + offset, 0, "-");
offset++;
}
}
return clone.join("");
}
alert(DashInsert("45739"));
Output: 45-7-3-9
Demo: http://jsfiddle.net/262Bf/
To complement the great answers already given, I would like to share an alternative implementation, that doesn't modify arrays in-place:
function DashInsert(num) {
var characters = num.split("");
var numbers = characters.map(function(chr) {
return parseInt(chr, 10);
});
var withDashes = numbers.reduce(function(result, current) {
var lastNumber = result[result.length - 1];
if(lastNumber == null || current % 2 === 0 || lastNumber % 2 === 0) {
return result.concat(current);
} else {
return result.concat("-", current);
}
}, []);
return withDashes.join("");
}
It's longer, but IMHO reveals the intention better, and avoids the original issue.