I am writing a little clicking game with javascript at the moment and I am currently stuck with a little challenge. I need it so that whenever i have clicked a button 10 times. my second value should increase by one. Maybe a little bit hard to understand, I'll try to explain it in code.
// Let's just say I have this variable.
var timesThatTheButtonHasBeenClickedTenTimes = 0;
// So let's say I have an amount of times clicked.
Amount = 0;
// Whenever I click the button..The Amount increases like this.
Amount++;
// so after one click the amount should be..
Amount = 1;
// I need it so that when the button has been clicked 10 times I want to display //that. Something like this.
timesThatTheButtonHasBeenClickedTenTimes = 1;
Should I do this with a while loop or what.
// Let's just say I have this variable.
var timesThatTheButtonHasBeenClickedTenTimes = 0;
// So let's say I have an amount of times clicked.
var amount = 0;
var counter = function () {
amount++;
if (amount === 10) {
amount = 0;
timesThatTheButtonHasBeenClickedTenTimes++;
}
document.getElementById('clicks').innerHTML = amount;
document.getElementById('hits').innerHTML = timesThatTheButtonHasBeenClickedTenTimes;
};
document.getElementById("mybutton").addEventListener("click", counter);
<button id='mybutton'>
Click me!
</button>
<p>
Clicks = <span id='clicks'>0</span>
</p>
<p>
10 times hits = <span id='hits'>0</span>
</p>
Hope it helps!
You could do something like:
var timesButtonClicked = 0;
var secondValue = 0;
if (timesButtonClicked === 10) {
secondValue++;
timesButtonClicked = 0;
} else {
timesButtonClicked++;
}
This is the very simple solution for you problem:
var clicks = 0;
Clicker = function() {
clicks++;
console.log('You clicked '+clicks+' times already.');
if(clicks == 10){
alert('Something what you want to alert.')
clicks = 0;
}
}
<button onclick="Clicker()">
Click me 10x times pls
</button>
One approach I'd suggest is:
function increment() {
// find the current number of times the <button> has been clicked,
// if the <button> has a data-current attribute we retrieve that
// attribute-value and parse it as a number in decimal format;
// if it does not have that custom data-* attribute we set the
// variable to 0:
let currentValue = this.dataset.current ? parseInt(this.dataset.current, 10) : 0;
// here we update the data-current attribute to the incremented value
// of the currentValue:
this.dataset.current = ++currentValue;
// we retrieve the element with the id of 'clicks', and set
// its textContent to the value held by the currentValue:
document.getElementById('clicks').textContent = currentValue;
// here we retrieve the element with an id of 'numberOfTens',
// and set its textContent to the floored value of the currentValue
// divided by 10:
document.getElementById('numberOfTens').textContent = Math.floor(currentValue / 10);
}
// here we retrieve the element with the id of 'clicker':
document.getElementById('clicker')
// and bind the increment() function (note the deliberate lack of
// parentheses) as the event-handler for the 'click' event:
.addEventListener('click', increment);
div:empty::before {
content: '0';
}
#clicks::after {
content: ' clicks.';
}
#numberOfTens::after {
content: ' tens of clicks.';
}
<button id="clicker">Click</button>
<div id="clicks"></div>
<div id="numberOfTens"></div>
References:
CSS:
:empty pseudo-class.
Pseudo-elements, ::before, ::after.
content property.
JavaScript:
document.getElementById().
EventTarget.addEventListener().
HTMLElement.dataset.
parseInt.
Pre-increment variable ++variableName.
Related
The Problem:
I can't seem to be able to get a list of buttons to change the value of their corresponding inputs.
I'm trying to code a cart system for my website, pretty standard. It involves a list of item, each of which have a section that includes two buttons for adding or subtracting the quantity of its corresponding item. These buttons surround the input that displays the current quantity (disabled so that the user must use the buttons to control it).
Everything is working, but I can't seem to figure out how to target the corresponding input of a button that is clicked so that it will change the value of that specific input.
What I've Tried:
I've figured out that if I add a [0] at the end of the "quantityInputs" variable then it will target the first input in the list, makes sense. But I don't want it to only target the first input, I want it to target the input that the button is associated with. Even then, when I test the plus button it only updates the input one time to 2 and then stops, which I only know because I'm printing the value to the console - it doesn't actually change the display on the webpage.
I've considered using a for loop to get the position of the input, but I'm not sure how to incorporate that into the code in order for it to work with the for loop that gets the position of the plus or minus buttons, or if that will even work.
Can anyone please help me out? I'd really appreciate it.
My Code:
HTML:
if (document.readyState == 'loading') {
document.addEventListener('DOMContentLoaded', ready)
} else {
changeQuantity()
}
function changeQuantity() {
var buttonUps = document.getElementsByClassName('item-quantity-up')
console.log('There are ' + buttonUps.length + ' plus buttons total.') // Tells you how many plus buttons there are.
for (var i = 0; i < buttonUps.length; i++) { // Get the positions of each plus button.
var button = buttonUps[i]
button.addEventListener('click', addQuantity) // When a plus button is clicked, run the addQuantity function.
}
var buttonDowns = document.getElementsByClassName('item-quantity-down')
console.log('There are ' + buttonDowns.length + ' minus buttons total.') // Tells you how many minus buttons there are.
for (var i = 0; i < buttonDowns.length; i++) { // Get the positions of each minus button.
var button = buttonDowns[i]
button.addEventListener('click', subQuantity) // When a minus button is clicked, run the subQuantity function.
}
}
function addQuantity(event) {
var quantityInputs = document.getElementsByClassName('cart-item-quantity') // Needs an index such as [0] in order to return a real number.
var inputValue = parseInt(quantityInputs.value) // Turns the value into an integer.
var max = quantityInputs.max // Retrieves the max value for the input.
if (inputValue >= max) {
inputValue = inputValue // If the quantity is greater than or equal to the max, then don't change the quantity.
} else {
inputValue = inputValue + 1 // If the quantity is less than the max, then add 1 to the quantity.
console.log(inputValue)
}
}
function subQuantity(event) {
var quantityInputs = document.getElementsByClassName('cart-item-quantity') // Needs an index such as [0] in order to return a real number.
var inputValue = parseInt(quantityInputs.value) // Turns the value into an integer.
var min = quantityInputs.min // Retrieves the min value for the input.
if (inputValue <= min) {
inputValue = inputValue // If the quantity is less than or equal to the min, then don't change the quantity.
} else {
inputValue = inputValue - 1 // If the quantity is greater than the min, then subtract one from the quantity.
console.log(inputValue)
}
}
<div class="cart-quantity-field">
<button class="item-quantity-down">-</button>
<input class="cart-item-quantity" type="number" min="1" max="20" value="1" disabled>
<button class="item-quantity-up">+</button>
</div>
You can manipulate the correct input field by doing the following:
On quantity-button click:
locate the clicked button's parent element
inside that parent, look for input with the correct class name
decide whether the button clicked should add or subtract one
add +1 or -1 respectively to the current value of the input
const allQuantityBtns = document.getElementsByClassName("quantity-btn");
Array.from(allQuantityBtns).forEach(btn => {
btn.addEventListener("click", e => {
const inputToChange = e.target.parentElement.querySelector(".cart-item-quantity");
const plusOrMinusOne = e.target.classList.contains("item-quantity-up") ? 1 : -1;
const newValue = parseInt(inputToChange.value) + plusOrMinusOne;
// validate newValue here. Eg: is it allowed to be smaller than zero?
inputToChange.value = newValue;
});
});
<div class="cart-quantity-field">
<button class="item-quantity-down quantity-btn">-</button>
<input class="cart-item-quantity" type="number" min="1" max="20" value="1" disabled>
<button class="item-quantity-up quantity-btn">+</button>
</div>
Note: you may wish to implement some validation:
stop the quantity from being too large or small before modifying the input's value
I thought that this onClick event in a For loop would help me but when I tried it, it still didn't work.
I am making a simple Battleship game, and while I'm trying to have the user click on only 4 squares to place on ship, the loop keeps going and doesn't stop after 4 tries. I have my onclick even handler in a for loop, but after 4 tries it doesn't stop. I've tried adding a count variable after the end, and even tried adding a break statement but can't get it to work.
Here's my code:
function placeShips() {
var playerTable = document.getElementById("mainPlayer");
var playerCells = playerTable.getElementsByTagName("td");
var count = 1;
alert("Please place the first ship. Click on 4 squares.");
while (count <= 4) {
for (i = 0; i < playerCells.length; i++) {
playerCells[i].onclick = placeBattleship;
}
count++;
}
}
The placeBattleship function contains the code to change the grid square to a background color of red to mark it. My problem is that once the user clicks 4 squares, you can keep going and click on more and more. I can't get the above for loop that calls the placeBattleship function to stop after the user clicks on 4 squares. I've tried putting it in a while loop, and even the solution in the above link, as well as moving the assignment of count, but can't get it to stop after x amount of times (in this case, 4).
Any ideas on what I'm doing wrong, or a better way to do it?
Wouldn't you consider to use jQuery?
Look your function much shorter:
function placeShips() {
$("td:lt(4)").click(placeBattleship);
}
You can testify on the code below:
<table>
<tr>
<td>1.1</td><td>2.1</td>
</tr>
<tr>
<td>1.2</td><td>2.2</td>
</tr>
<tr>
<td>1.3</td><td>2.3</td>
</tr>
</table>
<div id="console"></div>
<script>
$("td:lt(4)").each(function(){
$("#console").append("Content of "+ $(this).html() + "<br/>");
});
$("td:lt(4)").click(function(){
$("#console").append("Clicking "+ $(this).html() + "<br/>");
});
</script>
...or on my Plunker: https://plnkr.co/edit/yNZw6ZhkNfA9E0NdQg7V
So, now we have a solution that stop for 4th click on the squares:
function placeBattleship() {
var $shipDisplay = $("#shipDisplay");
var counter = $shipDisplay.data("counter");
if(counter++ < 4) {
$(this).css("background-color", "red");
$shipDisplay.data("counter", counter);
}
}
function placeShips() {
$("td").click(placeBattleship);
}
$(document).ready(function(){
placeShips();
});
I use a div with id shipDisplay to store a data-attribute for count the clicks.
Look at the plunker: http://plnkr.co/edit/PEba15PSLv2LK6qjY7AD?p=preview
You should separate priorities in your logic and removeEventListener when counter hits 4 , hopefully this helps you :
//defined outside the function
var counter = 0;
playerCells.addEventListener("click" , placeShips );
Then
function placeShips() {
if(counter <= 4){
//Move ship
placeBattleship();
//add to counter
counter++
}else{
//Remove click event if counter reaches 4 .
playerCells.removeEventListener("click" , doSomethingElse)
}
}
You question needs a bit clarification. To my current understanding, you need to move the checking of count to placeBattleship.
What you are doing is binding click to same tds 4 times, not limiting the number of event triggering to 4 times.
// pseudo code
var count = 4; // this is global
var currentCount = 0;
initFunc() {
// bind click events ONCE
}
startPlacing() {
// accept user click and place ship
// set currentCount to zero
}
placeShip() {
// the callback of user `click`
// check for currentCount == count then move on (no more placement)
// increase currentCount by 1
// place ship
}
Note that after an event is triggered, the listener will not be removed. Until you removeEventListener() from it, it will always be listening.
I'm writing the first item of an array to the screen, and would like to create Next/Previous buttons for array, but I can't get it to work. I have tried several methods, but I can't find suitable solution.
Can anyone help?
This is the last one I have tried:
<div>
<script type="text/javascript">
sav = new Array(
"first item",
"second item",
"third item",
);
document.write(sav[0] + " <br>");
</script>
</div>
<div>
Previous
Next!
</div>
Say you have an Array var arr = ['foo', 'bar', 'baz'];.
If you want to dynamically choose items from this Array, you'll need a new variable. Let's call this i and give it a default value var i = 0;
So far, arr[i]; // "foo" (i === 0)
Next and Previous
Now, lets write a function to choose the next item by modifying i. We may want to consider what we want to happen when i is bigger than (or equal to) arr.length as well.
function nextItem() {
i = i + 1; // increase i by one
i = i % arr.length; // if we've gone too high, start from `0` again
return arr[i]; // give us back the item of where we are now
}
Next, lets do the reverse, this time we might want to consider what should happen for negative i
function prevItem() {
if (i === 0) { // i would become 0
i = arr.length; // so put it at the other end of the array
}
i = i - 1; // decrease by one
return arr[i]; // give us back the item of where we are now
}
So far,
nextItem(); // "bar" (i === 1)
prevItem(); // "foo" (i === 0 as we did `0 + 1 - 1`)
// also
prevItem(); // "baz" (decreased on 0)
nextItem(); // "foo" (increased at end of arr)
Great, so we've got the basic algorithms down.
Connecting this to the DOM
First thing to note is that document.write is nearly always a bad idea. Instead, why not give our Elements some unique id attributes and use DOM methods in JavaScript after the Elements exist.
<div id="output"></div>
<div>
<span id="prev_button">Previous</span>
<span id="next_button">Next!</span>
</div>
So now we can access the first <div> in JavaScript as document.getElementById('output'), and the two <span>s similarly.
Now, let's set the initial text in the <div>, this is quite easy
document.getElementById('output').textContent = arr[0]; // initial value
// if i is still at it's default value, we could have used i instead of 0
Next, we need to add event listeners to the <span>s so they perform an action. The handler of each will set the text of the <div> in a similar way to above, but using the relevant function from earlier.
document.getElementById('prev_button').addEventListener(
'click', // we want to listen for a click
function (e) { // the e here is the event itself
document.getElementById('output').textContent = prevItem();
}
);
document.getElementById('next_button').addEventListener(
'click', // we want to listen for a click
function (e) { // the e here is the event itself
document.getElementById('output').textContent = nextItem();
}
);
This is great! Now the only thing left to do is make sure it runs "after the Elements exist". There are two ways to do this, either by putting the <script> element after the elements it uses, or by listening for the load event on window, i.e.
window.addEventListener('load', function () {
// DOM related JavaScript goes here
});
DEMO of everything together
If you want to do this multiple times or are mixing it with other JavaScript, you may need to consider variable name conflicts. The easiest way to get around this is by using an IIFE to create a "safe place" for your variables, but this answer is already long enough.
Try this way easier and corrected.
<script type="text/javascript">
var text = [
"first item",
"second item",
"third item"
];
var Current = 0;
document.getElementById("textHere").innerHTML = text[Current];
function Prev(){
if(Current == 0){
Current = text.length - 1;}
else{
Current--;}
document.getElementById("textHere").innerHTML = text[Current];
}
function Next(){
if(Current == text.length - 1){
Current = 0}
else{
Current++;}
document.getElementById("textHere").innerHTML = text[Current];
}
</script>
<div id="textHere"></div>
<div>
<button onclick="Next();">Next!</button>
<button onclick="Prev();">Previous</button>
</div>
Try this way, easier and corrected. -Alfa College Application Developer.
<script type="text/javascript">
var text = [
"first item",
"second item",
"third item"
];
var Current = 0;
document.getElementById("textHere").innerHTML = text[Current];
function Prev(){
if(Current == 0){
Current = text.length - 1;}
else{
Current--;}
document.getElementById("textHere").innerHTML = text[Current];
}
function Next(){
if(Current == text.length - 1){
Current = 0}
else{
Current++;}
document.getElementById("textHere").innerHTML = text[Current];
}
</script>
<div id="textHere"></div>
<div>
<button onclick="Next();">Next!</button>
<button onclick="Prev();">Previous</button>
</div>
I got a problem while writung a code for a Heatmap based on link clicks.
I have a Page with different articel teasers. When i click the link the artical itself opensup. Now i want to track in real time how often which articel is clicked so i can decide which articel is relevant to users and place it like on the first articel space and so on.
Therefor i wrote a function which tracks the clicks with a counter and show them in the div.
Now my problem is. That i cant write like 20 functions for counters and 20 for resets. I want to have one function which can decide which articel was clicked and add +1 to the counter of the link.
My Code for the counter and the reset + the link text gets red after more than 5 clicks.
var count1 = 0;
function heatmap(id) {
if(id==1){
count1++;
document.getElementById("count1").innerHTML = count1;
}
if(count1>=5){
document.getElementById("link1").style.color = "red";
}
}
function reset(id){
if(id==1){
count1=0;
document.getElementById("count1").innerHTML = 0;
}
}
My html code so far
<div style="text-align:center; font-size:20px; font-family: arial;">
<div id="link1" onclick="heatmap(1)">This is the first Link</div><br>
<div id="count1">0</div><br>
<button onclick="reset(1)">RESET</button>
<button onclick="save(1)">SAVE</button>
</div>
Now my main problem is that i only want one function for all the link tracking.
Is there a possibiblity to write the code in a way the variables are dynamicly so that the function can decide which link was clicked.
for example something like:
var count + ID = 0;
function heatmap(ID) {
count + ID ++;
document.getElementById("count" + ID).innerHTML = count+ID;
}
if(count + ID >=5){
document.getElementById("link + ID").style.color = "red";
}
}
function reset(id){
count + ID =0;
document.getElementById("count + ID").innerHTML = 0;
}
}
I already searched this homepage and did some google searches but all i found was working with arrays or lists. But i think this wouldnt realy work for me since i want to give my function an ID and later add this id to the varibale name like count + ID = count | count + ID = count2 same with the document.getElementById("count" + ID).innerHTML = count+ID; = document.getElementById("count1").innerHTML = count1;
As you can see the link got a onclick="heatmap(ID)" this ID will be added to every articel Link and will go from the first articel with 1 to the last articel with like 20.
If i change an Articel the counter will be resetet and the ID will be changed to its position. So there will always be a identifier with the ID which can be used for the counter.
You could loop through all articles and store a counter on each element which you update or reset once the specific button inside the article was clicked:
var articles = document.querySelectorAll('article');
for(var i=0; i < articles.length; i++) {
articles[i].querySelector('.save').addEventListener('click', updateCounter);
articles[i].querySelector('.reset').addEventListener('click', resetCounter);
articles[i]['counter'] = 0;
}
function updateCounter(ev) {
var article = ev.target.parentNode;
article.counter++;
article.querySelector('.counter').innerHTML = article.counter;
/* Some server synchronisation should go here */
}
function resetCounter(ev) {
var article = ev.target.parentNode;
article.counter = 0;
article.querySelector('.counter').innerHTML = article.counter;
/* Some server synchronisation should go here */
}
DEMO
But to permanently store the counters you have to synchronize your results with a server, respectively a database.
If you just want to use one function you could realize it like this:
var articles = document.querySelectorAll('article');
for(var i=0; i < articles.length; i++) {
articles[i].querySelector('.save').addEventListener('click', checkCounter);
articles[i].querySelector('.reset').addEventListener('click', checkCounter);
articles[i]['counter'] = 0;
}
function checkCounter(ev) {
var article = ev.target.parentNode,
button = ev.target;
if(button.classList[0] === 'save') {
article.counter++;
} else if(button.classList[0] === 'reset') {
article.counter = 0;
}
article.querySelector('.counter').innerHTML = article.counter;
}
DEMO
First, please take a look at my fiddle.
I'm trying to figure out a clean way of making the price next to each item change when any item is selected (in that group, you can image that there will be graphics cards etc in a different section which also will need the same functionality).
If its positive I need the class to be .positive and vice versa, and if the item is selected (+0) then the price difference wont be displayed.
This will also be used on checkbox's.
Non-working example.
You'll want to compare each selected item with items having the same name. In the .each() loop in CalculatePrice(), pass the checked item to this function:
function CalculateDiffs(item) {
var selectedPrice = +item.data("price");
item.siblings(".item_price").text("");
$(".calculation-item[name='"+item.attr("name")+"']").not(item).each(function(){
var price = +$(this).data("price");
var diff = (price-selectedPrice).toFixed(2);
if (diff >= 0) {
diff = "+"+diff;
}
$(this).siblings(".item_price").toggleClass("negative", diff < 0).text(diff);
});
}
As for checkboxes, the above function will take care of hiding the price when it is checked. To display the prices for unchecked checkboxes:
$(".calculation-item:checkbox:not(:checked)").each(function(){
$(this).siblings(".item_price").text("+"+$(this).data("price"));
});
Or, if you want to display the price of a checked checkbox as negative, use this instead:
$(".calculation-item:checkbox").each(function(){
var diff = (this.checked ? "-" : "+") + $(this).data("price");
$(this).siblings(".item_price").toggleClass("negative",this.checked).text(diff);
});
http://jsfiddle.net/gilly3/HpEJf/8/
Actually it's pretty straight forward, all you'll need to do is calculate the difference between the selected price and the price of all the options in the list. Eg, something like this:
$(".calculation-item").each(function(index) {
var my_cost = base_price + $(this).data("price");
var difference = Math.round(my_cost - base_cost);
});
I've created a working jsFiddle for you here: http://jsfiddle.net/HpEJf/6/. You'll need to implement decimal rounding etc but this should put you on the right track :)
If my understanding is correct, you want to display the cost difference from the previously selected radio button and the currently selected radio button.
To do that you need to keep track of the previously selected button. The only way I know of to do that is to set a variable outside the clickhandler scope to keep track of it and update the element in the clickhandler.
The rest is fairly straightforward. I updated your jsFiddle with an example of how to do it. The relevant code is below:
Adding at top of script:
//global for last checked/selected radio
var lastSelection = $(".calculation-item:checked");
//clear existing price diffs set by markup
$('span.processor_price').text('');
Added another function:
function priceDifference(oldPrice, newPrice) {
var difference = {
'cssClass': '',
'inCost': '0'
};
var fixedDiff = '';
var diff = newPrice - oldPrice;
diff = Math.ceil(Math.abs(diff * 100)) / 100;
fixedDiff = diff.toString();
if (newPrice < oldPrice) {
difference.cssClass = 'negative';
difference.inCost = '-' + fixedDiff;
} else if (newPrice > oldPrice) {
difference.cssClass = 'positive';
difference.inCost = '+' + fixedDiff;
}
/* else {
* must be the same, no reason for this block
* as the default empty string will suffice
* as will the cost difference of 0
}*/
return difference;
}
And changed your click handler to:
$(".calculation-item").click(function() {
var difference = {};
if (lastSelection) {
//get difference
difference = priceDifference($(lastSelection).data("price"), $(this).data("price"));
//change class
$(this).siblings('span.processor_price').addClass(difference.cssClass).text(difference.inCost);
$(lastSelection).siblings('span.processor_price').removeClass('positive').removeClass('negative').text('');
if (lastSelection !== this) {
lastSelection = this;
}
} else {
lastSelection = this;
}
CalculatePrice();
});