Satisfying button click condition to bring up a message in javascript - javascript

Sorry in advance if my code is really bad but I am just a beginner. I would like to create a word search puzzle using buttons. When the person is finished finding by clicking on all of the words which I am going to make from buttons I want a message to come up that they have completed the puzzle. So I created a sample here with 4 buttons but I can't seem to get my code to work. I want the message to come up in the div container once all the buttons have been clicked on. Am I on the right track here or way off? Any insight would be so much appreciated!
<html>
<p onclick="myFunction()" id="1" value=false >Button1</p>
<p onclick="myFunction()" id="2" value=false >Button2</p>
<p onclick="myFunction()" id="3" value=false >Button3</p>
<p onclick="myFunction()" id="4" value=false >Button4</p>
<div id="demo">Message displays here if all 4 buttons are clicked</div>
<script>
function myFunction(){
value = true;}
if(p 1){
value = true;}
if(p 2){
value = true;}
if(p 3){
value = true;}
if(p 4){
value = true;}
else{
document.getElementById("demo").innerHTML = "Congratulations you clicked on all of the buttons";}
}
</script>
</html>

You could use the buttons' data attributes to hold their state. (Note: for a more complex project, you probably don't want to do this)
Also, putting JS inline like onclick="myfunction()" is somewhat bad for your code - it encourages globals and makes JS logic harder to follow. So, I've shown an alternative using an IIFE, .querySelectorAll(), and .addEventListener():
// IIFE to keep variables out of the global scope
;(() => {
// NOTE: These are more flexible when they are arrays (thus, Array.from())
const btnEls = Array.from(document.querySelectorAll('.js-button'))
const msgEls = Array.from(document.querySelectorAll('.js-message'))
const handleButtonClick = ({ target: btnEl }) => {
btnEl.disabled = true // optional
btnEl.dataset.toggled = 'true' // using the DOM to hold data
if (btnEls.some(el => el.dataset.toggled !== 'true')) return
msgEls.forEach(el => {
el.textContent = 'Congratulations you clicked on all of the buttons'
})
}
// Our "onclick" equivalent
btnEls.forEach(el => el.addEventListener('click', handleButtonClick))
})()
<button class="js-button">Button1</button>
<button class="js-button">Button2</button>
<button class="js-button">Button3</button>
<button class="js-button">Button4</button>
<p class="js-message">Message displays here if all 4 buttons are clicked</p>
...There's probably a lot of syntax there you don't know but that example should be helpful for those learning from a more modern source. Since you're learning from something that uses older JS syntax, here's some older JS code that works about the same (but isn't as easy to maintain):
// IIFE to keep variables out of the global scope
;(function () {
// NOTE: These are more flexible when they are arrays (thus, Array.from())
var btnEls = Array.from(document.querySelectorAll('.js-button'))
var msgEls = Array.from(document.querySelectorAll('.js-message'))
function handleButtonClick(event) {
var btnEl = event.target
btnEl.disabled = true // optional
btnEl.dataset.toggled = 'true' // using the DOM to hold data
if (btnEls.some(function (el) {
return el.dataset.toggled !== 'true'
})) return
msgEls.forEach(function (el) {
el.textContent = 'Congratulations you clicked on all of the buttons'
})
}
// Our "onclick" equivalent
btnEls.forEach(function (el) {
el.addEventListener('click', handleButtonClick)
})
})()
<button class="js-button">Button1</button>
<button class="js-button">Button2</button>
<button class="js-button">Button3</button>
<button class="js-button">Button4</button>
<p class="js-message">Message displays here if all 4 buttons are clicked</p>

Here was my solution.
var set = []; //decalre an empty array
function myFunction(Id) {
console.log(Id); //the Id will be the vlaue from the button. For example button 1 has an Id of one as passed into by 'myFunction(1)
if (set.indexOf(Id) == -1) { //here we check to see if the Id number is in the array
set.push(Id); //if it's not in the array, we add it in
console.log(set);
console.log("length: " + set.length);
if (set.length > 3) { //if the lengthof the array is greater than three, all 4 buttons have been clicked.
document.getElementById("demo").innerHTML = "Congratulations you clicked on all of the buttons";
}
}
}
<p onclick="myFunction(0)">Button0</p>
<p onclick="myFunction(1)">Button1</p>
<p onclick="myFunction(2)">Button2</p>
<p onclick="myFunction(3)">Button3</p>
<div id="demo">Message displays here if all 4 buttons are clicked</div>

An easier way of doing this is with an event listener that listens to each button click, then makes the value of that button true, and then checks all the buttons to see if they are all clicked and if so output the congrats message
HTML
added classes to each button and removed the onclick function
<html>
<p class='button' id="1" value=false >Button1</p>
<p class='button' id="2" value=false >Button2</p>
<p class='button' id="3" value=false >Button3</p>
<p class='button' id="4" value=false>Button4</p>
<div id="demo">Message displays here if all 4 buttons are clicked</div>
</html>
JS
window.addEventListener('click', (e)=>{
var bool = true
if (e.target.classList.contains('button')) {
e.target.setAttribute('value', "true")
}
buttons = document.querySelectorAll('.button')
for (let i = 0; i < buttons.length; i++) {
console.log(buttons[i].getAttribute('value'))
if (buttons[i].getAttribute('value') == "false") {
bool = false
}
}
if (bool == true) {
document.getElementById("demo").innerHTML = "Congratulations you clicked on all of the buttons";
}
})

I would suggest this as an easy answer to understand javascript and html a little better:
HTML
<html>
<body>
<button onclick="myFunction(event)" name="button1">Button1</button>
<button onclick="myFunction(event)" name="button2">Button2</button>
<button onclick="myFunction(event)" name="button3">Button3</button>
<button onclick="myFunction(event)" name="button4">Button4</button>
<div id="demo">Message displays here if all 4 buttons are clicked</div>
</body>
</html>
JS
var foundButtons = {
button1: false,
button2: false,
button3: false,
button4: false,
};
function myFunction(event) {
foundButtons[event.target.name] = true;
for (var button in foundButtons) {
if (foundButtons.hasOwnProperty(button)) {
if (!foundButtons[button]) {
return
}
}
}
document.getElementById("demo").innerHTML = "Congratulations you clicked on all of the buttons";
}
What this does is that you have an object of the buttons or rather the words that must be clicked to show the message. Now when one of the buttons gets clicked, its property gets set to true. Then it iterates over the properties and ends the function with a return statement, if it finds a false value, which means there is a button that has not been clicked. When the function does not get stopped it will show the success message.

Related

Click outside an element doesn't work

I have this code:
function showAll(el){
var id = el.parentNode.id;
var all= document.getElementById(id).getElementsByClassName('items')[0];
if(all.style.display === 'block'){
all.style.display = 'none';
} else{
all.style.display = 'block';
window.addEventListener('mouseup', function(e){
document.getElementById('test').innerHTML = e.target.className;
if(e.target != all){
all.style.display = 'none';
}
});
}
}
<div id="parent">
<div class="selected" onClick="showAll(this);">
</div>
<div class="items" style="display: none">
</div>
</div>
Basically what i want to achieve is: click on selected to display items which is now hidden after that if i click again on selected or if i click outside of items(a random spot on that page or even on selected) i want to be able to hide items.
The problem is that without the EventListener when i click on selected it works to display items and then if i click again on selected it works to hide items but if i click on a random spot it doesn't work to close items.
But when i add EventListener and i click on selected it works to click a random spot to close items but it doesn't work to click selected again to close items.
Can anybody help me with a full JavaScript explanation, please?
You're going to want to use highly reusable code. I use change() and id_() on my web platform all of the time and it's very direct and simple. In the below example the second parameter will make the class empty (you can also use id_('items').removeAttribute('class') for a cleaner DOM (Document Object Model)).
HTML
<input onclick="change(id_('items','');" type="button" value="Display Items" />
<div clas="hidden" id="items"><p>Items here.</p></div>
CSS
.hidden {display: none;}
JavaScript
function change(id,c)
{
if (id_(id)) {id_(id).className = c; if (id_(id).className=='') {id_(id).removeAttribute('class');}}
else if (id) {id.className = c; if (id.className=='') {id.removeAttribute('class');}}
else {alert('Error: the class id \''+id+'\' was not found or has not yet been imported to the DOM.\n\nNew class intended: '+c);}
}
function id_(id)
{
if (id == '' && window['console']) {console.log('Developer: empty id called from: '+id_.caller.toString().split('function ')[1].split('(')[0]);}
return (document.getElementById(id)) ? document.getElementById(id) : false;
}
This code exists from years of refining the same platform instead of industry standard drama of pointlessly changing things. You are two clicks from finding more highly reusable functions on my platform's JavaScript documentation from the link in my profile.

Get variables from button css in Javascript and use them as id

Hi I need a bit of help modifying my script. What I want to do:
I have a small and easy script. It changes the class of an container so I have influence on the behaviour and looking of the container. In my scenario the buttons open a div with a music player.
My problem is that I need to declare all buttons as a script. The button ID is in my case the onclick function (see code).
So when I have 10 or twenty links I need also everytime to modify the script. My idea is to have a script wich gets feed their variables by id's and classes of containers. So I need not to modify the script file.
// JavaScript Document
function AudioFF() {
var FFplayer = document.getElementById(x);
if (FFplayer.classList.contains("audio-hidden")) {
FFplayer.classList.remove("audio-hidden");
FFplayer.classList.add("audio-shown");
} else {
FFplayer.classList.remove("audio-shown");
FFplayer.classList.add("audio-hidden");
Array.prototype.slice.call(document.querySelectorAll('audio')).forEach(function(audio) {audio.pause();});
}
};
dbbtn.onclick = function() {
x = "deepblue";
AudioFF();
};
swbtn.onclick = function() {
x = "spacewalk";
AudioFF();
};
fbtn.onclick = function() {
x = "forest";
AudioFF();
};
drbtn.onclick = function() {
x = "dreamrhythm";
AudioFF();
};
My idea was to use the same class of a button as an id for the container who needs to fade in with a string. The button has e.g. the class btn_a, btn_b … etc. The containers has the id btn_a, btn_b … I wanted the script to catch the class of the button and use this classname as a variable for getElementById. The closebutton is also using the same script to close the container. Thanks for help :-)
I will recommend to use data attribute instead
example like this:
//register listener like this
var btns = document.querySelectorAll('[data-music]');
btns.forEach(function(elm) {
elm.addEventListener('click', function(e) {
//your function
console.log(this.dataset.music);
})
})
<!--your links-->
<div id="m1"></div>
<div id="m2"></div>
<div id="m3"></div>
<!--just add data-music attribute make it the same with your div id and all set-->
<button data-music="m1">play m1</button>
<button data-music="m2">play m2</button>
<button data-music="m3">play m3</button>
You should be able to set a data tag attribute to the buttons and just read the variable from that:
<button id="myButton" data="variableForMyButton" />
document.getElementById(myButton).onClick = function(e){
x = e.target.getAttribute('data')
}
If multiple params are required you add additional data tags:
<button id="myButton" data="variableForMyButton" data-action="someSweetAction" />
Thanks guys, that was what I was looking for. My function is now like this:
The play button and closebutton are working.
<button data-music="m1">Deep Blue</button>
<div id="m1">Container Content</div>
var btns = document.querySelectorAll('[data-music]');
btns.forEach(function(elm) {
elm.addEventListener('click', function(e) {
//function
var FFplayer = document.getElementById((this.dataset.music));
if (FFplayer.classList.contains("audio-hidden")) {
FFplayer.classList.remove("audio-hidden");
FFplayer.classList.add("audio-shown");
} else {
FFplayer.classList.remove("audio-shown");
FFplayer.classList.add("audio-hidden");
Array.prototype.slice.call(document.querySelectorAll('audio')).forEach(function(audio) {audio.pause();});
}
})
})
And here in jquery. Thanks to you all. You show me the way :-)
jQuery (document).ready(function($){
var btns = $('[data-music]');
$(btns).each(function() {
$('[data-music]').on('click', function(e) {
var FFplayer = $(this).data('music');
$("#" + FFplayer).toggleClass("audio-hidden audio-shown");
});
});
})

How to assign a javascript function by classname

I have multiple buttons (generated by php) for a shopping cart application:
<button class="addtocart" id="<?php echo $code; ?>">
<span id="addtocartbutton">Add to cart</span>
</button>
I want to update my cart using a function:
function AddtoCart() {
alert("Added!");
}
Later, I want to find the id ($code) created by the button which called it (not sure how to do that also, but maybe that's another question). And so I tried this:
document.getElementsByClassName("addtocart").addEventListener("click", AddtoCart());
But it doesn't work. It was working using an onclick, but I understand that the right way to do it by creating an EventListener. Also, I cannot use the on() function in jQuery, because I am forced to use jQuery Version 1.6 which does not have it.
I have looked at https://stackoverflow.com/a/25387857/989468 and I can't really assign it to the parent which is a p tag, because I obviously don't want the other elements in the p tag to be assigned this function.
While the answers given are correct, there is another way: Event Delegation
Attach the listener to a SINGLE thing, in this case the document body and then check to see what element was actually clicked on:
Warning: Typed on the fly: Untested
// Only needed *once* and items may be added or removed on the fly without
// having to add/remove event listeners.
document.body.addEventListener("click", addtoCart);
function addtoCart(event) {
var target = event.target;
while(target) {
if (target.classList.contains('addtocart')) {
break;
}
// Note: May want parentElement here instead.
target = target.parentNode;
}
if (!target) {
return;
}
var id = target.dataset.id;
alert(id + " added!");
}
You should attach click event to every element with class addtocart, since getElementsByClassName() return an array of all objects with given class name so you could use for to loop through everyone of them and associate it with function you want to trigger on click (in my example this function called my_function), check example bellow :
var class_names= document.getElementsByClassName("addtocart");
for (var i = 0; i < class_names.length; i++) {
class_names[i].addEventListener('click', my_function, false);
}
Hope this helps.
function my_function() {
alert(this.id);
};
var class_names= document.getElementsByClassName("addtocart");
for (var i = 0; i < class_names.length; i++) {
class_names[i].addEventListener('click', my_function, false);
}
<button class="addtocart" id="id_1">button 1</button>
<button class="addtocart" id="id_2">button 2</button>
<button class="addtocart" id="id_3">button 3</button>
<button class="addtocart" id="id_3">button 4</button>
I'll show some of the errors you had in your code, then I'll show you how can you improve it so that you can achieve what you want, and I also show that it works with buttons dynamically added later:
First and foremost, you need to pass the function reference (it's name) to the addEventListener! You have called the function, and passed whatever it returned. Instead of:
document.getElementsByClassName("addtocart").addEventListener("click", AddtoCart());
It should've been:
document.getElementsByClassName("addtocart").addEventListener("click", AddtoCart);
Second: document.getElementsByClassName("addtocart") returns a NodeList, you can't operate on it, you need to operate on it's elements: document.getElementsByClassName("addtocart")[0], [1],....
Third, I would suggest you to use the data-... html attribute:
<button class="addtocart" id="addtocart" data-foo="<? echo $code; ?>">
This way you can pass even more data. Now you can get the $code as:
document.getElementById('addtocart').dataset.foo
// el: the button element
function AddtoCart(el) {
// this is the id:
var id = el.id;
// and this is an example data attribute. You can have as many as you wish:
var foo = el.dataset.foo;
alert(id + " (" + foo + ") added!");
}
// Try add a div or something around the area where all the buttons
// will be placed. Even those that will be added dynamically.
// This optimizes it a lib, as every click inside that div will trigger
// onButtonClick()
document.getElementById("buttons").addEventListener("click", onButtonClick);
// this shows that even works when you dynamically add a button later
document.getElementById('add').onclick = addButton;
function addButton() {
var s = document.createElement("span");
s.text = "Add to cart";
var b = document.createElement("button");
b.innerHTML = 'Third <span class="addtocartbutton">Add to cart</span>';
b.className = "addtocart";
b.id="third";
b.dataset.foo="trio";
// note the new button has the same html structure, class
// and it's added under #buttons div!
document.getElementById("buttons").appendChild(b);
}
// this will gett triggered on every click on #buttons
function onButtonClick(event) {
var el = event.target;
if (el && el.parentNode && el.parentNode.classList.contains('addtocart')) {
// call your original handler and pass the button that has the
// id and the other datasets
AddtoCart(el.parentNode);
}
}
<div id="buttons">
<button class="addtocart" id="first" data-foo="uno">First <span class="addtocartbutton">Add to cart</span></button>
<button class="addtocart" id="second" data-foo="duo">Second <span class="addtocartbutton">Add to cart</span></button>
</div>
<button id="add">Add new button</button>
<html>
<head>
<script>
window.onload=function{
var btn = document.getElementsByName("addtocartbtn")[0];
btn.addEventListener("click", AddtoCart());
}
function AddtoCart() {
alert("Added!");
}
</script>
</head>
<body >
<button class="addtocart" name ="addtocartbtn" id="<?php echo $code; ?>" > <span id="addtocartbutton">Add to cart</span></button>
</body>
</html>
Actually class in Javascript is for multiple selection you should provide index like an array.
<button class="addtocart"> <span id="addtocartbutton">Add to cart</span></button>
<script type="text/javascript">
document.getElementsByClassName("addtocart")[0].addEventListener("click", AddtoCart);
function AddtoCart() {
alert("Added!");
}
</script>
Also your second parameter was wrong don't use parentheses.
Applying parentheses means it will call the function automatically when loaded, and will not call the function after that.

Click visible button in protractor?

I have a page which looks something like this. It's a wizard with steps. Depending on the "step" scope variable, a different part of the wizard is shown:
<div ng-show="step == 'first'">
<button>Next</button>
</div>
<div ng-show="step == 'second'">
<button>Next</button>
</div>
<div ng-show="step == 'third'">
<button>Next</button>
</div>
To click the next button I run into problems though. Because there are three of them. The following code returns all of them:
var next = element(by.buttonText('Next'));
And doing:
next.click();
will click the first one. How can I find the visible button only, and click that one?
First I was confused by isDisplayed returning a promise. This function is what I came up with:
function clickButton(text) {
var buttons = element.all(by.buttonText(text));
buttons.each(function(button) {
button.isDisplayed().then(function(isVisible) {
if (isVisible) {
button.click();
}
})
});
}
Which can be used like this:
clickButton('next');
Here is a bit more cleaner version in terms of understanding that uses filter() to filter a single visible button and click it:
function clickButton(text) {
var buttons = element.all(by.buttonText(text));
var visibleButton = buttons.filter(function(button) {
return button.isDisplayed().then(function(isVisible) {
return isVisible;
});
}).first();
visibleButton.click();
}
As a bonus, you'll also get an error if there are no visible buttons found, as opposed to your current approach which would not fail in this case.
You should be able to chain the elements to specify which next button you want to click.
var firstNext = element(by.css('div[ng-show="step == \'first\'"]')).element(by.buttonText('Next'));
var secondNext = element(by.css('div[ng-show="step == \'second\'"]')).element(by.buttonText('Next'));
var thirdNext = element(by.css('div[ng-show="step == \'third\'"]')).element(by.buttonText('Next'));
// We are on the first step
firstNext.click();
// We are on the second step
secondNext.click();
// We are on the third step
thirdNext.click();

Popup form on hover - how to make it the only one on the page?

I have 5 buttons 'Free call' on my site. On hover on them pops up contact form. I have a number of problems with it:
How to make the form be the only one on the page? I mean, from different buttons must be shown the same form. (For ex. I filled in the form in one place and when I hover other button, I see message 'You're done' or smth like that)
How to make the showing function work only once for every button? (The code below)
I tried to solve this problems but my methods didn't work
HTML
I have 5 such buttons on the page in different places
function showForm() {
var currentButton = $(this);
if ( currentButton.find('.popover-form') !== undefined ) {
var freeCallForm = "<form class=\"popover-form free-call-form\"><label for=\"\">Name</label><input type=\"text\"> <label for=\"\">Phonenum</label><input type=\"text\" value=\"+375\"><button>Call me!</button> </form>";
currentButton.append(freeCallForm);
}
}
$('.main-btn').on('mouseover', showForm);
<script src="https://ajax.googleapis.com/ajax/libs/jquery/1.11.0/jquery.min.js"></script>
<div class="main-btn free-call">
<p>Use free call
<br/>
<i class="glyphicon glyphicon-chevron-down"></i>
</div>
This function above unfortunately doesn't work. With if I tried to make function work only when .main-btn hasn't .popover-form.
And other problem is that on hover on different buttons anyway appends NEW form for every button. I can't find correct solution for this problem.
var isOpen = false;
function showForm() {
var currentButton = $(this);
if ( currentButton.find('.popover-form') !== undefined && !isOpen) {
var freeCallForm = "<form class=\"popover-form free-call-form\"><label for=\"\">Name</label><input type=\"text\"> <label for=\"\">Phonenum</label><input type=\"text\" value=\"+375\"><button>Call me!</button> </form>";
isOpen = true;
currentButton.append(freeCallForm);
}
}
$('.main-btn').on('mouseover', showForm);
//on modal close set isOpen back to false
The solution is the append() method. It moves DOM elements, not copies them (I thought so).
So I inserted my <form id="free-call-form"> to the end of the document, before </body>.
JS
function showForm() {
var currentButton = $(this);
if ( ( currentButton.find('.popover-form') !== undefined && !currentButton.existsFreeCall ) ) {
var freeCallForm = $('#free-call-form');
currentButton.append(freeCallForm);
currentButton.existsFreeCall = true;
}
}
$('.main-btn').on('mouseover', showForm);
In this code the same form moves from one to another button without copying and multiple appending.

Categories

Resources