I have a bunch of product buttons like:
<button class='prd-class' data-prd-id='1'>
Product 1
</button>
<button class='prd-class' data-prd-id='2'>
Product 2
</button>
And I have a button click function like so:
$('.prd-class').click(function(){
$('.prd-class').removeClass('cls-focus'); //remove any focused product
$(this).addClass('cls-focus'); //then focus on the selected one
$('#selected-prd-name').text($(this).data('prd-name'));
... etc
});
As you can see, it uses this object reference inside the function heavily.
Now there is another situation where at page load I want the lines inside this function to be executed.
Since there are multiple product buttons, I want to ensure that the I am simulating the click event of the required one.
$(document).ready(function()
{
$("button[data-prd-id='"+prd_id+"']").click();
});
But this does not work. How can I change the code to execute the code lines correctly?
I am not sure about your requirements. However, this demo might give you some ideas to resolve your issues.
HTML:-
<button class='prd-class' data-prd-id='1'>Product 1</button>
<button class='prd-class' data-prd-id='2'>Product 2</button>
<div>
Selected Product ID: <span id="selected-prd-name"></span>
</div>
CSS:-
.cls-focus {
border: 1px solid red;
background-color: brown;
}
JavaScript:-
(function () {
var $prdClass = $('.prd-class'),
$selectedPrdId = $('#selected-prd-name'),
prdClassClickHander = function () {
var $self = $(this);
$prdClass.removeClass('cls-focus');
$self.addClass('cls-focus');
$selectedPrdId.text($self.data('prd-id'));
},
init = function () {
$prdClass.on("click", prdClassClickHander);
};
$(document).ready(init);
}());
// Simulate the click on DOMReady
$(document).ready(function () {
var prd_id = 1;
$("button[data-prd-id='" + prd_id + "']").trigger('click');
});
JSFiddle Demo:-
http://jsfiddle.net/w3devjs/e27jQ/
Related
var countWrong = 0;
(Button1, Button3, Button4, Button5, Button6).addEventListener('click', () => {
countWrong += 1;
});
console.log(countWrong)
I can not figure out what I'm doing wrong. When the buttons are clicked I want to increment 1 to countWrong.
There are two problems here:
(Button1, Button3, Button4, Button5, Button6).addEventListener
You can't call a method on multiple objects like that. I assume you want something like:
[Button1, Button3, Button4, Button5, Button6].forEach(b =>
b.addEventListener('click', () => {
countWrong += 1;
})
);
EDIT: I assumed Button... where variables, but if they are IDs, you'll need to look them up first, maybe like this:
document.querySelectorAll("#Button1, #Button3, #Button4, #Button5, #Button6").forEach( ... )
Also console.log(countWrong) will always display 0, because the event handlers won't have been called yet.
You can do what you need with jquery
var countWrong = 0;
$('#Button1, #Button3, #Button4, #Button5, #Button6').on('click', () => {
countWrong += 1;
console.log(countWrong)
});
And the console.log() has to be inside your onclick function otherwise your log will only give you the initial value 0 once before any button was pressed
You have written the right code however you see the wrong results.
Because, you are printing the countWrong only once after initialising it.
So when you initialise for the first time, it's value will be zero and it prints it.
And when ou click the buttons, the value of that variable will be updated however you won't be able to see because the console.log present in outer code has already been executed ( but the value is updating ).
And your logic of binding the events for multiple ids is not as same as you wrote, change a bit.
try this :
var countWrong = 0;
['Button1', 'Button3', 'Button4', 'Button5', 'Button6'].forEach(function(e) {
e.addEventListener('click', () => {
countWrong += 1;
console.log(countWrong)
});
});
As mentioned in my comment you can't assign an event listener to multiple elements like that. The other answers have covered iterating over the buttons with forEach - here's an example with event delegation.
Add one listener to a parent container which catches events as they "bubble" up the DOM from its children (the buttons). Within the handler check that the clicked element is a button (and has a "count" class), and then increase/log the count.
const buttons = document.querySelector('.buttons');
buttons.addEventListener('click', handleClick);
let count = 0;
function handleClick(e) {
if (e.target.matches('button')) {
if (e.target.classList.contains('count')) {
console.log(++count);
}
}
}
button { border-radius: 5px; }
.count { background-color: lightgreen; }
.count:hover { cursor: pointer; }
Green buttons increase the count
<section class="buttons">
<button type="button" class="count">Button 1</button>
<button type="button">Button 2</button>
<button type="button" class="count">Button 3</button>
<button type="button">Button 4</button>
</section>
Currently, I use the following solution:
<button onclick="initiate('ok2')" id="btn1">Initiate</button>
<button id="btn2">Send data</button>
function initiate(ok) {
document.getElementById("btn2").addEventListener("click", receiveData);
}
function receiveData(event) {
console.log(event);
}
The benefit of this approach lies in the named function receiveData, which is recognized as the same function and is not added repeatedly.
Steps to reproduce:
Press the 'Initiate' button multiple times
Press 'Send data'
Result: console log is printed only once
I want to utilize the same approach, but add an attribute to the function. I tried the bind approach, but the event listener is added multiple times. As a result, the console log is also printed multiple times.
Example:
function initiate(ok) {
document.getElementById("btn2").addEventListener("click", receiveData.bind(null, ok));
}
function receiveData(event, ok) {
console.log(event);
console.log(ok);
}
Is it possible to pass an argument to a function and not create duplicate event listeners? Ideally, it would be preferred not to delete event listeners, like in the current solution.
Here is my version with the recommended ways of delegating and setting and getting data attribute
A user cannot click what is not visible so no need to initiate the button, just unhide it
document.addEventListener("click", function(e) {
let btn = e.target
if (btn.matches("#btn1")) {
let targetBTN = document.getElementById(btn.dataset.target);
targetBTN.hidden = false;
} else if (btn.matches("#btn2")) {
console.log(btn.dataset.field);
}
});
<button id="btn1" data-target="btn2">Initiate</button>
<button id="btn2" data-field="ok2" hidden>Send data</button>
// when the window loads add a click handler to the button of choice
window.addEventListener('load', (event) => {
console.log('page is now loaded');
document.getElementById("btn2").addEventListener("click", receiveData)
});
function receiveData(event) {
console.log(event);
}
or as suggested in comments, add the click handler inline.
You need to tel it if it is inited or not..
let data = "";
let init = true;
function initiate(ok) {
data = ok
if(init ){
document.getElementById("btn2")
.addEventListener("click", receiveData);
init = false
}
}
function receiveData(event) {
console.log( data );
}
<button onclick="initiate('ok2')" id="btn1">Initiate</button>
<button id="btn2">Send data</button>
It looks like the one goal is to only allow the second button to be able to be used when the first button is clicked.
So, I attached an event listener to the document. Then used data attributes on the buttons to determine if the start button can be used or not. And just for display I used CSS to hide the start button if its not allowed to be used just yet
document.addEventListener("click",function(e){
let btn = e.target
if(btn.matches(".btn-start")){
let targetBTN = document.querySelector(`[data-id='${btn.dataset.target}']`)
targetBTN.setAttribute("data-initiated","true");
}
else if(btn.dataset.initiated == "true"){
console.log(btn.dataset.field);
}
});
[data-initiated="false"]{
display:none
}
[data-initiated="true"]{
display:inline-block
}
<button data-target="send2" class="btn-start">Initiate</button>
<button data-initiated="false" data-field="ok2" data-id="send2" class="btn-send">Send data</button>
I'm using HTML slim for the code below.
.page
.paper
button.button.js-copier I copy things
- content_for :js_includes do
javascript:
var startingHtml = $('.page').html();
function initializePlugin() {
$('.js-copier').each(function () {
$(this).on('click', function () {
$('.page').append(startingHtml);
$(document).trigger('page-refreshed');
});
});
}
// Run it right away
initializePlugin();
$(document).on('page-refreshed', initializePlugin);
Is there a way to fix the fact that when I click on the "I copy things" button, it creates multiple copies of the button as it is iterating over all the button from the button that was selected?
Also, is there a better way to write this code. All I'm trying to do is duplicate the button anytime I click on any buttons(first and any new button created buttons)
-Anthony
First change this:
$('.js-copier').each(function () {
$(this).on('click', function () {
...
to this:
$('.page').on('click', '.js-copier', function () {
...
Read this to understand https://learn.jquery.com/events/event-delegation/#event-propagation
Then remove the 'page-refreshed' event because you don't need it:
$(document).trigger('page-refreshed');
...
$(document).on('page-refreshed', initializePlugin);
Demo solution:
var startingHtml = $('.page').html();
function initializePlugin() {
$('.page').on('click', '.js-copier', function () {
$('.page').append(startingHtml);
});
}
// Run it right away
initializePlugin();
<script src="https://ajax.googleapis.com/ajax/libs/jquery/2.1.1/jquery.min.js"></script>
<div class="page">
<div class="paper">
<button class="button js-copier"> I copy things</button>
</div>
</div>
I have got a button wrapped inside a div.
The problem is that if I click the button, somehow the click function is triggered from the div instead of the button.
Thats the function I have for the click event:
$('#ButtonDiv').on('click', '.Line1', function () {
var myVariable = this.id;
}
Thats my HTML (after is is created dynamically!!):
<div id="ButtonDiv">
<div class="Line1" id="Line1Software">
<button class="Line1" id="Software">Test</button>
</div>
</div>
So now myVariable from the click function is 'Line1Software' because the event is fired from the div instead of the button.
My click function hast to look like this because I am creating buttons dynamically.
Edit:
This is how I create my buttons and wrapp them inside the div
var c = $("<div class='Line1' id='Line1Software'</div>");
$("#ButtonDiv").append(c);
var r = $("<button class='waves-effect waves-light btn-large btnSearch Line1' id='Software' draggable='true'>Software</button>");
$("#Line1Software").append(r);
You code with the example html actually fires twice, once for each element since the event will bubble up and match both elements (since they are .Line1)
If you are trying to add an event listener to the button you should probably be using $('#Software') instead of $('#ButtonDiv')
The real problem is that neither the div nor the button have an id.
You code with the example html actually fires twice, once for each element since the event will bubble up and match both elements (since they are .Line1)
If you only want it to match the innermost element, then use return false to stop the bubbling.
$('#ButtonDiv').on('click', '.Line1', function () {
var myVariable = this.id;
console.log(myVariable);
return false;
});
var c = $("<div class='Line1' id='Line1Software'></div>");
$("#ButtonDiv").append(c);
var r = $("<button class='waves-effect waves-light btn-large btnSearch Line1' id='Software' draggable='true'>Software</button>");
$("#Line1Software").append(r);
<script src="https://ajax.googleapis.com/ajax/libs/jquery/2.1.1/jquery.min.js"></script>
<div id="ButtonDiv">
</div>
Your question is a bit odd because you give yourself the answer... Look at your code, you are explicitly using event delegation:
$('#ButtonDiv').on('click', '.Line1', function () {
var myVariable = this.id;
});
This code means that, for each click on a .Line1 element, the event will be delegated to the #ButtonDiv element (thanks to bubbling).
If you do not want this behavior, just do that:
$('.Line1').on('click', function () {
var myVariable = this.id;
});
This is also correct:
$('.Line1').click(function () {
var myVariable = this.id;
});
I am trying to toggle visibility of signup and signin boxes if sign in and sign up buttons are clicked. I am trying to use only pure javascript.
I wrote simple html and javascript as below:
<div>
<button class="signin">sign in</button><button class="signup">sign up</button>
<div class="signin-box" style="display: none;">
<form class="signin-form">
<label>username<input></label><label>password<input></label><button type="submit">signin</button>
</form>
</div>
<div class="signup-box" style="display: none;">
<form class="signup-form">
<label>username<input></label><label>password<input></label><button type="submit">signup</button>
</form>
</div>
</div>
javascript part:
var signupButton = document.getElementsByClassName('signup')[0];
var signinButton = document.getElementsByClassName('signin')[0];
var signupBox = document.getElementsByClassName('signup-box')[0];
var signipBox = document.getElementsByClassName('signin-box')[0];
console.log("box: ", signupBox, "button: ",signupButton);
var toggleVisible = function(item){
if (item.style.display === 'none'){
return item.style.display = 'block';
}else{
return item.style.display = 'none';
}
};
window.onload = function(){
signupButton.onclick = toggleVisible(signupBox);
signinButton.onclick = toggleVisible(signipBox);
};
The problem here is that the javascript toggleVisible is automatically activated even if i never clicked the buttons.
as a result, the signin-box and signup-box both gets display:block property.
How do i solve this problem?
You're calling the function, not passing it in. Just wrap your function call in an anonymous function:
signupButton.onclick = function() {
toggleVisible(signupBox);
};
If you don't care about older browsers, you can also simplify your code a little if you put your JavaScript at the bottom of the <body> tag and add a rule to your CSS:
document.querySelector('.signup').addEventListener('click', function() {
document.querySelector('.signup-box').classList.toggle('hidden');
}, false);
document.querySelector('.signin').addEventListener('click', function() {
document.querySelector('.signin-box').classList.toggle('hidden');
}, false);
And the CSS:
.hidden {
display: none;
}
I would recommend to use a standard JavaScript method addEventListener() to attached onclick event listener to the button.
It has following advantages over different solution:
You can attach an event handler to an element without overwriting existing event handlers.
You can add many event handlers of the same type to one element, i.e
two "click" events.
In your code it will look like
window.onload = function(){
signupButton.addEventListener("click", function() { toggleVisible(signupBox); });
signinButton.addEventListener("click", function() { toggleVisible(signipBox); });
};
Current code invokes toggleVisible(..) method and assigns its result to the button attribute, which is not one would expect.
signupButton.onclick = toggleVisible(signupBox);