First button click, change colour, Second click change font family - javascript

I have a simple HTML with a paragraph and button. I want to carry out different commands on every click of the button. For first click, change paragraph colour, on second click change font family, on third click copy the innerHTML 5 times(pls explain how to do this), on four or more clicks, change innerHTML to "DONE".
var clicks = 0;
var a = document.getElementById("output");
function go() {
clicks ++;
moves();
};
function moves() {
if (clicks = 1) {
a.style.color = "red";
}
else if (clicks = 2) {
a.style.fontFamily = "sans-serif";
}
}
<html>
<head>
<title></title>
</head>
<body>
<button onclick=go();>ClickMe</button>
<p id="output">Change Me</p>
</body>
<script src="q2.js" type="text/javascript"></script>
</html>

you have used = instead of ==.= are used for assignment and for compare you must use == or ===.
also you don't need to move function and I moved it to go function
var clicks = 0;
var a = document.getElementById("output");
function go() {
clicks ++;
if (clicks == 1) {
a.style.color = "red";
}
if (clicks == 2) {
a.style.fontFamily = "sans-serif";
}
if (clicks == 3) {
a.innerText = a.innerText+a.innerText+a.innerText+a.innerText;
}
if (clicks == 4) {
a.innerText = "done";
}
};
<body>
<button onclick=go();>ClickMe</button>
<p id="output">Change Me</p>
</body>

You can use something like an array of functions. See the comments for explanation under every function.
$(function () {
// Let's start with an array of functions that needs to be executed.
var fns = [function () {
// First one.
// Change Para Colour.
$("#output").css("color", "#00f");
}, function () {
// Second one.
// Change Para Font.
$("#output").css("font-family", "monospace");
}, function () {
// Third one.
// Copy the inner HTML 5 times. You can use something like String.repeat().
$("#output").html($("#output").html().repeat(5));
}, function () {
// Fourth one.
// Done.
$("#output").html("Done.");
}];
var counter = 0;
$("button").click(function () {
if (counter >= 4)
return false;
fns[counter]();
counter++;
});
});
<script src="https://ajax.googleapis.com/ajax/libs/jquery/2.1.1/jquery.min.js"></script>
<button>ClickMe</button>
<p id="output">Change Me</p>

Use repeated to make 5 copies and store it in a variable.
const content = document.getElementById('content');
let copy5;
let count = 0;
content.addEventListener('click', function(e) {
count += 1;
if (count === 1) {
content.style.color = 'green';
}
if (count === 2) {
content.style.fontFamily = "Arial, Helvetica, sans-serif"
}
if (count === 3) {
copy5 = content.innerText.repeat(5);
console.log(copy5)
}
if (count === 4) {
content.innerHTML = 'DONE';
count = 0;
}
})
<div id="content">I have a simple HTML with a paragraph and button. I want to carry out different commands on every click of the button. For first click, change paragraph colour, on second click change font family, on third click copy the innerHTML 5 times(pls explain
how to do this), on four or more clicks, change innerHTML to "DONE".</div>

You can create a queue - implemented by a simple array - of functions like below (just a simplified example which you can base on):
var changeColor = function() {
a.style.color = "red";
};
var changeFont = function() {
a.style.fontFamily = "sans-serif";
};
var moves = [changeColor, changeColor, changeFont, changeFont, changeFont];
function go() {
var move = moves.shift(); // get and remove the first move from the queue
if (move) move();
}
The idea is storing the moves in that queue in the order you want to execute them. So, if you want a certain function to be executed 4 times, you put it 4 times in the queue, followed by the next function in the amount you want, and so on and so forth.
The shift function gets the next move to be executed. You need to call only that function, go, to execute the next move.
With this approach, you don't need to count the number of clicks.

as far i understood from your question, the below code can work fine for you... in your question it said "on third click copy the innerHTML 5 times", loop the same function for the 5 times.
var count = 0;
function go(){
count++;
switch(count){
case 1: document.getElementById('output').style.color = 'green'; break;
case 2: document.getElementById('output').style.fontFamily = 'sans-serif'; break;
case 3: copyText('output'); break;
case 4: document.getElementById('output').innerHTML = '"DONE"';
}
}
function copyText(containerid){
if (document.selection) {
var range = document.body.createTextRange();
range.moveToElementText(document.getElementById(containerid));
range.select().createTextRange();
document.execCommand("Copy");
} else if (window.getSelection) {
var range = document.createRange();
range.selectNode(document.getElementById(containerid));
window.getSelection().addRange(range);
document.execCommand("Copy");
}
}

You've got the right idea, but you are missing the actual click event handling registration.
Also, it's cleaner and easier to maintain if you add/remove CSS classes, rather than modifying individual styles.
Lastly, because of the particular if logic you have, a switch statement is easier to read and slightly better in performance.
var clicks = 1;
var o = document.getElementById("output");
var b = document.getElementById("btn");
// Store original text
var original = o.textContent;
// Set up a click event handler:
b.addEventListener("click", moves);
function moves() {
switch (clicks) {
case 1:
o.classList.add("one");
break;
case 2:
o.classList.add("two");
o.classList.remove("one");
o.textContent = repeatText(5, o.textContent);
break;
case 3:
o.classList.add("three");
o.classList.remove("two");
o.textContent = original;
break;
case 4:
// Intentional fall-through to the default
default:
o.classList.remove("three");
o.textContent = "Done";
break;
}
// Can't have a space before or after ++
clicks++;
}
function repeatText(numTimes, data){
var result = "";
for(var i = 0; i < numTimes; i++){
result += data;
}
return result;
}
.one {
color:red;
}
.two {
font-family:sans-serif;
}
.three {
font-weight:bold;
}
<button id="btn">ClickMe</button>
<p id="output">Change Me</p>

Related

Why doesn't my if statement respond to the changes I made to the variables?

var count = 0;
if(count % 2 == 0) {
for (let i = 0; i < squareStorage.length; i++) {
squareStorage[i].addEventListener("click", function() {
console.log("This is: " + i)
console.log(count%2)
count++;
console.log(count);
});
}
}
else if(count % 2 == 1) {
console.log(count%2)
for (let i = 0; i < squareStorage.length; i++) {
squareStorage[i].addEventListener("click", function() {
console.log("This is (no.2): " + i)
count++;
console.log(count);
}, false);
}
}
Those are part of my code. I wanted the variable count to change as I click on a bunch of divs which I threw into the squareStorage variable. I tried by increasing variable count whenever I click. However, my if statement somehow keeps on running, even when count % 2 is not 0.
Its a common mistake, you need to add your events seperately and then in the event call the code.
Here is example.
let count = 0;
// This method will deal with the logic on each click.
// NOTE: we are not re-doing our events.
const processClick = () => {
if(count%2 == 0) {
console.log(`This is one: count ${count}`);
} else {
console.log(`This is two: count ${count}`);
}
count++;
};
// When document loads we will find all divs and add a click event.
document.addEventListener('DOMContentLoaded', () => {
// Find all our DIV elements and add a click event to them.
document.querySelectorAll('div')
.forEach(div => div.addEventListener('click', processClick));
});
<div>Click</div>
<div>Click</div>
<div>Click</div>
<div>Click</div>
<div>Click</div>
I think you've forgotten to remove the old event listeners which you can do with removeEventListener.
eg:
function myClickFunction {
// ... do stuff for first click function
}
// when loading the 2nd click function you run this
squareStorage[i].removeEventListener('click', myClickFunction)

JS: setInterval running as if there were multiple intervals set

So, I've been trying to figure out JS, and what better way to do so than to make a small project. It's a small trivia game, and it has a question timer I've made using setInterval. Unfortunately, after answering multiple questions, the interval's behaviour gets very weird - it runs the command twice every time. I guess it's my faulty implementation of buttonclicks?
By the way, if my code is awful I am sorry, I've been desperate to fix the issue and messed with it a lot.
function startGame(){
if (clicked === true){
return;
}
else{
$("#textPresented").html("Which anthem is this?");
$("#button").css("display", "none");
currentCountry = getRndInteger(0,8);
console.log(currentCountry);
var generatedURL = anthemnflags[currentCountry];
console.log(generatedURL);
audios.setAttribute("src", generatedURL);
audios.play();
$("#button").html("I know!");
$("#button").css("display", "block");
$("#button").click(function () {
continueManager();
});
y=10;
console.log("cleared y" + y);
x = setInterval(function(){
y = y - 1;
console.log("Counting down..." + y)
}, 1000);
console.log("INTERVAL SET");
}
}
Here is the console output:
cleared y10 flaggame.js:59:17
INTERVAL SET flaggame.js:64:17
AbortError: The fetching process for the media resource was aborted by the user agent at the user's request. flaggame.js:49
Counting down...9 flaggame.js:62:20 ---- THESE TWO ARE BEING PRINTED AT THE SAME TIME
Counting down...8 flaggame.js:62:20 ---- THESE TWO ARE BEING PRINTED AT THE SAME TIME
Counting down...7 flaggame.js:62:20
Counting down...6 flaggame.js:62:20
Counting down...5 flaggame.js:62:20
Counting down...4 flaggame.js:62:20
Counting down...3 flaggame.js:62:20
Counting down...2 flaggame.js:62:20
Counting down...1 flaggame.js:62:20
Counting down...0
THE REST OF MY CODE:
function middleGame(){
$("#button").css("display", "none");
var n = document.querySelectorAll(".flagc").length;
correctIMG = getRndInteger(0,n-1);
showFlags();
var taken = new Array();
for (var i = 0; i < n; ++i){
if (i === correctIMG){
images[i].attr("src", "res/" + flagsfiles[currentCountry]);
taken[currentCountry] = true;
}
else{
var randomFlag = getRndInteger(0, flagsfiles.length);
if (randomFlag !== currentCountry && taken[randomFlag] !== true){
images[i].attr("src", "res/" + flagsfiles[randomFlag]);
taken[randomFlag] = true;
}
}
}
$(".flagc").click(function(){
clickregister(this);
});
}
function continueManager(){
if (!clicked){
audios.pause()
clearInterval(x);
x = 0;
clicked = true;
middleGame();
return;
}
}
function clickregister(buttonClicked){
if ($(buttonClicked).attr("id") != correctIMG){
points = points - 1;
flagARR[$(buttonClicked).attr("id")].css("display", "none");
console.log("INCORRECT");
}
else{
if (y >= 0) {
var addedPoints = 1 + y;
points = points + addedPoints;
$("#points").html(points);
}
else{
points = points + 1;
}
hideFlags();
clicked = false;
startGame();
}
}
$(function(){
hideFlags();
$("#textPresented").html("When you're ready, click the button below!");
$("#button").html("I am ready!");
$("#button").click(function () {
if (!gameStarted){
gameStarted = true;
alert("STARTING GAME");
startGame();
}
});
});
Basically this is how it works:
When the "I am ready" button is clicked, startGame() is called. It plays a random tune and counts down, until the player hits the "I know" button. That button SHOULD stop the interval and start the middleGame() function, which shows 4 images, generates a random correct image and awaits input, checks if it's true, then launches startGame() again.
The first and second cycles are perfect - after the third one things get messy.
I also noticed that the "INCORRECT" log gets printed twice, why?
EDIT: here is the minimized code that has the same issue:
var x;
var gameStarted = false;
var y;
var clicked;
$(function(){
$("#button").click(function () {
if (!gameStarted){
gameStarted = true;
startGame();
}
});
});
function startGame(){
console.log("startgame()");
if (clicked === true){
return;
}
else{
console.log("!true");
$("#button").css("display", "block");
$("#button").click(function () {
continueManager();
});
y=10;
x = setInterval(function(){
y = y - 1;
console.log(y);
}, 1000);
}
}
function continueManager(){
if (!clicked){
clearInterval(x);
x = 0;
clicked = true;
middleGame();
return;
}
}
function middleGame(){
$("#button").css("display", "none");
var taken = new Array();
$(".flagc").click(function(){
clickregister(this);
});
}
function clickregister(buttonClicked){
console.log("clickgregister");
//Irrelevant code that checks the answers
clicked = false;
startGame();
}
EDIT2: It appears that my clickregister() function gets called twice, and that function then calls startGame() twice.
EDIT3: I have found the culprit! It's these lines of code:
$(".flagc").click(function(){
console.log("button" + $(this).attr("id") + "is clicked");
clickregister(this);
});
They get called twice, for the same button
I fixed it!
It turns out all I had to do was to add
$(".flagc").unbind('click');
Before the .click() function!
You need to clear the interval first then call it again. You can do that by creating a variable outside of the event listener scope and in the event listener check if the variable contains anything if yes then clear the interval of x. After clearing the interval you can reset it.
Something like this:
<button class="first" type="submit">Button</button>
const btn = document.querySelector('.first');
let x;
btn.addEventListener("click", () => {
x && clearInterval(x)
x = setInterval(() => console.log("yoo"), 500)
})
This is because if you don't clear the interval of x it will create a new one on every button press.

javascript change background and play sound with one button

I'm building a clock inspired from the link below with added features like the single party button will play a music and change the BodyBGcolor per second.
https://codepen.io/codifiedconcepts/pen/bwgxRq
The music plays and pauses fine, but the BG starts changing but doesn't stop if I click to pause, and starts flickering and gets faster if I click the button again.
var partyTime = false;
var catMusic = new Audio("media/party.mp3");
function partyEvent() {
// partyTime and catMusic are defined outside
// otherwise they get re-defined without changing the old definition
if (partyTime === false) {
partyTime = true;
catMusic.play();
partyBtn.innerHTML = "PARTY OVER";
} else {
partyTime = false;
catMusic.pause();
partyBtn.innerHTML = "PARTY TIME";
}
}
var i = 0;
function changeBG() {
var color = ["red", "blue", "brown", "green"];
document.body.style.backgroundColor = color[i];
i = (i + 1) % color.length;
if (partyTime === true) {
var initBG = setInterval(changeBG, 1000);
} else {
clearInterval(initBG);
}
}
I have another function which changes the BGcolor 5 times in a day, for morning, noon, evening etc.. as a switch statement, I'm showing one case here..
switch (true) {
case hour <= 5:
imgTxt.innerHTML = "GET SOME SLEEPZ BRO";
catImg.style.background = "url('img/earlyMorning.jpg')";
catImg.style.backgroundSize = "cover";
document.body.style.backgroundColor= "#2d3037";
clockBody.style.color = "#99ffcc";
break;
please help this noob, and sorry for the indentation, it gets all same after pasting here..
if (partyTime === true) {
var initBG = setInterval(changeBG, 1000);
} else {
clearInterval(initBG);
}
Here you are creating initBG local to if block. In the else block initBG is undefined so it does not stop the interval process.
Solution: Define initBG outside the partyEvent function.
var initBG;
if (partyTime === true) {
initBG = setInterval(changeBG, 1000);
} else {
clearInterval(initBG);
}

execute function in created and inserted DOM element

My intention is very simple: I have a newSpan() function, that creates a new span and inserts it before the first child of the main element (or appends it if main is empty), and a letterTyper() function, that fills the inserted element with the string stored in a CONTENT constant while generating a sort of backwards typing effect. The idea is to create a new element and then triggering the effect inside it a given number of times with a loop in window.onload.
But when I fill the window.onload anonymous function with
window.onload = function() {
newSpan();
letterTyper();
newSpan();
letterTyper();
}
What I end up with in the DOM is
<main>
<span id="#span1">lorem ipsum</span>
<span id="#span0"></span>
</main>
I also tried to use a DOMContentLoaded event, to no effect. Why is that? What am I doing wrong?
My code:
const CONTENT = 'lorem ipsum';
var main = document.querySelector('main');
var spanId = 0;
var charCount = CONTENT.length;
window.onload = function() {
newSpan();
letterTyper();
newSpan();
letterTyper();
}
function newSpan() {
var newSpan = document.createElement('span');
var isEmpty = main.innerHTML === '';
newSpan.setAttribute('id', '#span' + spanId);
if (isEmpty) {
main.appendChild(newSpan);
} else {
main.insertBefore(newSpan, document.getElementById('#span' + (spanId - 1)));
}
spanId++;
}
function letterTyper() {
var targetSpan = main.firstChild;
targetSpan.textContent = CONTENT.substring(charCount, charCount + 1) + targetSpan.textContent.substring(0, targetSpan.textContent.length);
charCount--;
if ( charCount < 0) {
clearTimeout(timer);
charCount = CONTENT.length;
} else {
timer = setTimeout('letterTyper()', 100);
}
}
setTimeout is asynchronous. When you call letterTyper for the first time, it will return to your window.onload and trigger the next newSpan() and letterTyper().
That means that the letterTyper loop of the first span interferes with the second loop, because the first loop hasn't finished when the second one is started. In other words, the second loop is never created, but all calls of letterTyper will see the #span1 element (the second span element) as the first child of main.
You have to wait until the first loop is finished before you start the second loop. I suggest you take a look at Promises.
I changed a few things in your code so that is now uses promises:
const CONTENT = 'lorem ipsum';
var main = document.querySelector('main');
var spanId = 0;
var charCount = CONTENT.length;
window.onload = function() {
// start the first loop
letterTyper(newSpan()).then(function () {
// the first loop has finished, start the second loop
return letterTyper(newSpan());
}).then(function () {
// the second loop has finished, start the third loop
return letterTyper(newSpan());
});
}
function newSpan() {
var newSpan = document.createElement('span');
var isEmpty = main.children.length === 0;
newSpan.setAttribute('id', '#span' + spanId);
if (isEmpty) {
main.appendChild(newSpan);
} else {
main.insertBefore(newSpan, document.getElementById('#span' + (spanId - 1)));
}
spanId++;
charCount = CONTENT.length; // reset the character count
return newSpan;
}
function letterTyper(span) {
return new Promise(function (resolve, reject) {
// executes one tick (adds one character and calls itself after 100ms)
var tick = function () {
// prepend a new character
span.textContent = CONTENT[charCount -= 1] + span.textContent;
if (charCount > 0) {
// call tick again in 100ms
setTimeout(tick, 100);
} else {
// loop is finished, the "then" part will be called
resolve();
}
};
// start the loop
setTimeout(tick, 100);
});
}
<main></main>

Increase and decrease size of font separately

This function decreases OR increases the font size of memedotcomtop and memedotcomtop2 at the same time, once I click to do so. I want to decrease and increase the size of each separately. More specifically you can see on the Image below
I have two text boxes, a plus and a minus button on each
When i want to decrease or increase the size of the text in the first box(memedotcomtop ), it decreases or increases also the size of the text in the second box(memedotcomtop2 )
my code is:
layer.add(memedotcomtop2);
layer.draw();
var textmemeheight2 = stage.getHeight();
layer.draw();
layer.add(memedotcomtop);
layer.draw();
var textmemeheight = stage.getHeight();
layer.draw();
function lowertopsize()
{
if(memefontsize > 10 )
{
memefontsize = memefontsize -1;
memedotcomtop.fontSize(memefontsize);
layer.draw()
}
if(memefontsize2 > 10){
memefontsize2 = memefontsize2 -1;
memedotcomtop2.fontSize(memefontsize2);
layer.draw();
}
}
function increasetopsize()
{
memefontsize2 = memefontsize2 +1;
memedotcomtop2.fontSize(memefontsize2);
memefontsize = memefontsize +1;
memedotcomtop.fontSize(memefontsize);
layer.draw();
}
document.getElementById('meme-top-smaller').addEventListener('click', function() {
lowertopsize();
}, false);
document.getElementById('meme-top-bigger').addEventListener('click', function() {
increasetopsize();
}, false);
document.getElementById('meme-top-smaller2').addEventListener('click', function() {
lowertopsize();
}, false);
document.getElementById('meme-top-bigger2').addEventListener('click', function() {
increasetopsize();
}, false);
I'm using this library: kinetic-v5.0.1.min.js
Try this code.
layer.add(memedotcomtop2);
layer.draw();
var textmemeheight2 = stage.getHeight();
layer.draw();
layer.add(memedotcomtop);
layer.draw();
var textmemeheight = stage.getHeight();
layer.draw();
function lowertopsize() {
if (memefontsize > 10) {
memefontsize = memefontsize - 1;
memedotcomtop.fontSize(memefontsize);
layer.draw()
}
}
function lowertopsize2() {
if (memefontsize2 > 10) {
memefontsize2 = memefontsize2 - 1;
memedotcomtop2.fontSize(memefontsize2);
layer.draw();
}
}
function increasetopsize() {
memefontsize = memefontsize + 1;
memedotcomtop.fontSize(memefontsize);
layer.draw();
}
function increasetopsize2() {
memefontsize2 = memefontsize2 + 1;
memedotcomtop2.fontSize(memefontsize2);
layer.draw();
}
document.getElementById('meme-top-smaller').addEventListener('click', function () {
lowertopsize();
}, false);
document.getElementById('meme-top-bigger').addEventListener('click', function () {
increasetopsize();
}, false);
document.getElementById('meme-top-smaller2').addEventListener('click', function () {
lowertopsize2();
}, false);
document.getElementById('meme-top-bigger2').addEventListener('click', function () {
increasetopsize2();
}, false);
Note:
Create separate functions for each action and don't include memefontsize and memefontsize2 in one function.
Here's a worked example. How you choose to climb through the DOM tree is up to you. The important bit is that you can locate each of the 6 elements that you need to care about - the 4 buttons and the two text containers.
I've also chosen to use the TR elements that contain each row, as an easy means of keeping track of the current level of zoom, ready to be incremented or decremented in response to a button press.
The substantial difference between my approach and the one taken by both yourself and JohnR, is that we only have one function for increments and one for decrements. The function locates the element that triggered it in the DOM, before using this information to alter elements based on their relative position to the original triggering button.
This offers a few advantages:
1) You dont have duplicated code, which is subject to error as changes are made and all copies are updated.
2) You aren't limited in the number of elements on the page you can use this on - there's no need to write new (substantially identical) event handlers.
<!DOCTYPE html>
<html>
<head>
<script>
"use strict";
window.addEventListener('load', onDocLoaded, false);
function onDocLoaded()
{
// get the table
var tbl = document.getElementById('tgtTbl');
// get each of the row elements
var rows = tbl.getElementsByTagName('tr');
// and make them hold a variable that tracks their current zoom level.
rows[0].zoomLevel = 1;
rows[1].zoomLevel = 1;
// get array of 4 buttons. -,+, -,+
var btns = document.getElementsByTagName('button');
// and connect them to their handlers
btns[0].addEventListener('click', onMinusBtnPressed, false);
btns[1].addEventListener('click', onPlusBtnPressed, false);
btns[2].addEventListener('click', onMinusBtnPressed, false);
btns[3].addEventListener('click', onPlusBtnPressed, false);
}
function onPlusBtnPressed(evt)
{
// determine which button triggered the event
var btn = this;
// determine the TD and TR elements that contain this button
var containingCell = btn.parentNode;
var containingRow = containingCell.parentNode;
// grab the zoom level back from the TR element
var curZoom = containingRow.zoomLevel;
containingRow.zoomLevel += 0.1;
// the text is simply contained within a TD - the first element in the row
var targetCell = containingRow.childNodes[0];
// update the font-size
targetCell.setAttribute('style', 'font-size: ' + (curZoom*100) + '%');
}
function onMinusBtnPressed(evt)
{
var btn = this;
var containingCell = btn.parentNode;
var containingRow = containingCell.parentNode;
var curZoom = containingRow.zoomLevel;
containingRow.zoomLevel -= 0.1;
var targetCell = containingRow.childNodes[0];
targetCell.setAttribute('style', 'font-size: ' + (curZoom*100) + '%');
}
</script>
<style>
</style>
</head>
<body>
<div>
<table id='tgtTbl'>
<tr><td>Your top text</td><td><button>-</button><button>+</button></td></tr>
<tr><td>Your bottom text</td><td><button>-</button><button>+</button></td></tr>
</table>
</div>
</body>
</html>

Categories

Resources