Event delegation with bind? (Javascript) - javascript

You know how there are times when you want to use one eventlistener for multiple elements? Like this:
divWithManyLinks.addEventListener("click", function(event) {
console.log(event.target.textContent);
}
//--> text content of the clicked link
And you know how there are times when you want to use bind with an eventlistener to change the scope of the eventhandler? For instance, you might need to reference 'this' and point to something specific.
What if you want to have one eventlistener for multiple elements and use bind at the same time, is that possible?
In my case, I want to be able to go from one method (Example.prototype.methodA) to one of two other methods in the same object (Example.prototype.methodB or Example.prototype.methodC) based on what button is clicked. Because the eventlistener is placed inside of methodA the other methods will be referenced with this.methodB and this.methodC. I could possibly implement two eventlisteners with bind separately, but is it possible to have just one eventlistener?
Example.prototype.methodA = function() {
// addEventListener that listens on both buttons and executes either this.methodB or this.methodC based on what button is clicked.
}
Example.prototype.methodB = function() {
// do stuff
}
Example.prototype.methodC = function() {
// do stuff
}
If this is bad practise or if there is a better way to do it, please let me know.

You can do that, yes. Here's an example:
Example.prototype.methodA = function() {
someContainerElement.addEventListener("click", function() {
if (/* `event.target` is a match for the first button*/) {
this.methodB();
} else {
this.methodC();
}
}.bind(this), false);
};
Of course, it doesn't have to be an if, could be a switch or a map lookup or...
Live Example:
function Example(element, name) {
this.name = name;
this.element = element;
this.output = element.querySelector(".output");
}
Example.prototype.methodA = function() {
this.element.addEventListener("click", function() {
if (event.target.name == "B") {
this.methodB();
} else {
this.methodC();
}
}.bind(this), false);
}
Example.prototype.methodB = function() {
this.output.innerHTML =
prep(this.name).toLowerCase();
};
Example.prototype.methodC = function() {
this.output.innerHTML =
prep(this.name).toUpperCase();
};
function prep(text) {
return text.replace(/&/g, "&").replace(/</g, "<");
}
new Example(document.getElementById("one"), "one").methodA();
new Example(document.getElementById("two"), "two").methodA();
<div id="one">
The "one" element:
<br>
<input type="button" name="B" value="Lower">
<input type="button" name="C" value="Upper">
<span class="output"></span>
</div>
<div id="two">
The "two" element:
<br>
<input type="button" name="B" value="Lower">
<input type="button" name="C" value="Upper">
<span class="output"></span>
</div>

Related

How do I add another onclick function after the vote function? [duplicate]

Can we put two JavaScript onclick events in one input type button tag? To call two different functions?
This one works:
<input type="button" value="test" onclick="alert('hey'); alert('ho');" />
And this one too:
function Hey()
{
alert('hey');
}
function Ho()
{
alert('ho');
}
.
<input type="button" value="test" onclick="Hey(); Ho();" />
So the answer is - yes you can :)
However, I'd recommend to use unobtrusive JavaScript.. mixing js with HTML is just nasty.
The HTML
click
And the javascript
// get a cross-browser function for adding events, place this in [global] or somewhere you can access it
var on = (function(){
if (window.addEventListener) {
return function(target, type, listener){
target.addEventListener(type, listener, false);
};
}
else {
return function(object, sEvent, fpNotify){
object.attachEvent("on" + sEvent, fpNotify);
};
}
}());
// find the element
var el = document.getElementById("btn");
// add the first listener
on(el, "click", function(){
alert("foo");
});
// add the second listener
on(el, "click", function(){
alert("bar");
});
This will alert both 'foo' and 'bar' when clicked.
There is no need to have two functions within one element, you need just one that calls the other two!
HTML
<a href="#" onclick="my_func()" >click</a>
JavaScript
function my_func() {
my_func_1();
my_func_2();
}
You can attach a handler which would call as many others as you like:
<a href="#blah" id="myLink"/>
<script type="text/javascript">
function myOtherFunction() {
//do stuff...
}
document.getElementById( 'myLink' ).onclick = function() {
//do stuff...
myOtherFunction();
};
</script>
You could try something like this as well
<a href="#" onclick="one(); two();" >click</a>
<script type="text/javascript">
function one(){
alert('test');
}
function two(){
alert('test2');
}
</script>

Handling multiple inputs with a single onfocus handler in javascript [duplicate]

Example 1:
element1.addEventListener("input", function() {
// this function does stuff
});
Example 2:
element1 && element2.addEventListener("input", function() {
// this function does stuff
});
It might not be correct grammatically, but is there a way I can give two elements the same event listener at the same time (same line) instead of having to write them apart?
Well, if you have an array with the elements you could do:
let elementsArray = document.querySelectorAll("whatever");
elementsArray.forEach(function(elem) {
elem.addEventListener("input", function() {
//this function does stuff
});
});
Event Bubbling is the important concept in javascript, so if you can add event on DOM directly, you can save some lines of code, no need for looping :
document.addEventListener('click', function(e){
if(e.target.tagName=="BUTTON"){
alert('BUTTON CLICKED');
}
})
If you don't want to have a separate elementsArray variable defined you could just call forEach from an unnamed array with the two elements.
[ Element1, Element2 ].forEach(function(element) {
element.addEventListener("input", function() {
this function does stuff
});
});
One line
document.querySelectorAll("whatever").forEach(elem => elem.addEventListener("input", fn))
I cannot claim credit for this solution but I found a great solution here.
https://www.kirupa.com/html5/handling_events_for_many_elements.htm
var theParent = document.querySelector("#theDude");
theParent.addEventListener("click", doSomething, false);
function doSomething(e) {
if (e.target !== e.currentTarget) {
var clickedItem = e.target.id;
alert("Hello " + clickedItem);
}
e.stopPropagation();
}
I always recommend delegation - if the inputs are in the same container, then you can do this
window.addEventListener("DOMContentLoaded", function() { // on page load
document.getElementById("inputContainer").addEventListener("input", function(e) { // passing the event
const tgt = e.target;
const id = tgt.id;
console.log("You typed in",id)
});
});
<div id="inputContainer">
<h1>Start typing or paste</h1>
<input id="element1">
<input id="element2">
</div>
Example:
const element1 = document.querySelector("#element1");
const element2 = document.querySelector("#element2");
[element1, element2].map(element => element.addEventListener("click", function() {
/*some expressions :)*/
}))
If you are using Javascript through Electron and you have a list of buttons, you can use this code to add an EventListener to each button.
I'm actually using this method because classical Javascript methods (map(), forEach() ...) weren't supported anymore.
let buttons = document.getElementsByClassName('className');
for(let i = 0; i<buttons.length; i++){
buttons[i].addEventListener('click', () => {
/*put your code here*/
});
}
Maybe it will help you
let all_btn = document.querySelectorAll("button");
all_btn.forEach(function(btn) {
btn.addEventListener("click", function() {
console.log(this.innerHTML + " is clicked")
});
});
// one line code
// let all_btn=document.querySelectorAll("button");all_btn.forEach(function(n){n.addEventListener("click",function(){console.log(this.innerHTML+" is clicked")})});
<button>button 1</button>
<button>button 2</button>
<button>button 3</button>
The easiest way so far I've learned.
// Get an array of buttons from the page
var buttons = document.querySelectorAll(".btns");
// Loop through the resulting array
for(var i = 0; i < buttons.length; i++){
buttons[i].addEventListener("click", function() {
console.log("Hello World");
});
}
You can add an event listener to multiple elements using the path key of the click event object.
document.addEventListener('click', function(e){
//e.path[0].id;
//e.path[0].tagName;
//e.path[0].className;
if(e.path[0].className==="my-element"){
console.log("clicked");
}
})
Example for initializing one unique event listener specific to each element.
You can use the slider to show the values in realtime, or check the console.
On the <input> element I have a attr tag called data-whatever. You can use that to customize each event listener further.
sliders = document.querySelectorAll("input");
sliders.forEach(item=> {
item.addEventListener('input', (e) => {
console.log(`${item.getAttribute("data-whatever")} is this value: ${e.target.value}`);
item.nextElementSibling.textContent = e.target.value;
});
})
.wrapper {
display: flex;
}
span {
padding-right: 30px;
margin-left: 5px;
}
* {
font-size: 12px
}
<div class="wrapper">
<input type="range" min="1" data-whatever="size" max="800" value="50" id="sliderSize">
<em>50</em>
<span>Size</span>
<br>
<input type="range" min="1" data-whatever="OriginY" max="800" value="50" id="sliderOriginY">
<em>50</em>
<span>OriginY</span>
<br>
<input type="range" min="1" data-whatever="OriginX" max="800" value="50" id="sliderOriginX">
<em>50</em>
<span>OriginX</span>
</div>
If you have a DOM Collection, I suggest you to use the for ... of
In this MDN web doc you can see the details, but, for example, if you have:
HTMLCollection(6) [a.example, a.example, a.example, a.example, a.example, a.example]
You can:
let arrayElements = document.getElementsByClassName('example');
for (let element of arrayElements) {
element.addEventListener("click", function() {
console.log('Whoa! You clicked me')
});
And ta-dah! ;)
Here's what I used to set a click evenhandler on every span in my HTML (each span contains an emoji). When you click it, it will alert the emoji in the sample code.
Array.from(document.querySelectorAll("span")).map(element => element.addEventListener("click", function() {
alert(element.innerHTML);
}));
div{background: whitesmoke;}
span{ont-size:x-large;
cursor:pointer;}
<div>
<span>😀</span>
<span>😁</span>
<span>😂</span>
<span>😃</span>
<span>😄</span>
<span>😅</span>
<span>😆</span>
<span>😇</span>
<span>😈</span>
<span>😉</span>
<span>😊</span>
<span>😋</span>
</div>
First include jQuery then after you have included, add this script below.
Html code:
<script>
$('.greadingButton').on('click', function () {
$('.greadingButton').removeClass('selected');
$(this).addClass('selected');
});
</script>

Switch Div value with class attribute

I want to switch value from div to input and submit.
This's my codes so far
HTML
<form id="forms" action="content.php" method="post">
<input id="foo" type="hidden" value"">
</form>
<div class="btn" value="1" width="40" height="40"></div>
<div class="btn" value="2" width="40" height="40"></div>
Javascript
function $(v) {
return document.getElementById(v);
}
var btn = document.getElementsByClassName('btn');
for(i=0; i<btn.length; i++) {
btn[i].addEventListener('click', function() {
btn.getAttribute('value') = $('foo').value;
$('forms').submit();
}, false);
}
Why it dont work? can't be clicked? thx
I think you are doing the assignment wrong. You need to assign the value of the div button to your hidden foo field. Also, btn is the array of all buttons, you can use this inside event handler callback to reference the button that was clicked since this context is bound to the element that has the attached event. I think the following is what you want:
(function() {
function $(v) {
return document.getElementById(v);
}
var btn = document.getElementsByClassName('btn');
for (var i = 0; i < btn.length; i++) {
btn[i].addEventListener('click', function() {
// assign what was clicked (this) to the foo hidden value
$('foo').value = this.getAttribute('value');
// now submit
$('forms').submit();
}, false);
}
}());
Edit: Example using Array's forEach instead (which I assume would be available in your execution environment since you are using getElementsByClassName method.
(function() {
function $(v) {
return document.getElementById(v);
}
var buttons = document.getElementsByClassName('btn');
// each element of the array is passed to the provided callback
buttons.forEach(function (button) {
button.addEventListener('click', function() {
// assign what was clicked (this) to the foo hidden value
$('foo').value = this.getAttribute('value');
// now submit
$('forms').submit();
}, false);
});
}());
im not sure what the purpose of this is,
but if you insist on using divs as radio buttons or w.e
use data attributes,
like so
<div id="div1" data-value="1"></div>
and you can use jquery to get the attribute like this:
var div1 = $('#div1').data('value')
or
var div1 = $('#div1').attr('data-value');
on click listeners also with jquery
$('#div1').on('click', function(){
// do your thing here
...
})
Firstly, I don't think divs should have a value attribute. Maybe you should switch it to data-value, which can be used easily in jQuery:
<form id="forms" action="content.php" method="post">
<input id="foo" type="hidden" value"">
</form>
<div class="btn" data-value="1" width="40" height="40"></div>
<div class="btn" data-value="2" width="40" height="40"></div>
As for the javascript:
$('.btn').on('click', function() {
$(this).data('value', $('#foo').val());
$('#forms').submit();
});

Getting the collection in a jQuery plugin

Basically, what I am trying to do is create a bbcode editor with a textbox, some buttons and jQuery. Here is my form:
<div class="form-group">
<div class="btn-group btn-group-sm">
<button type="button" class="btn glyphicon bbcode" rel="bold"><b>B</b></button>
<button type="button" class="btn glyphicon bbcode" rel="italic"><i>I</i></button>
</div>
</div>
<div class="form-group">
<textarea class="bbcode" rel="editor" cols="100" rows="12"></textarea>
</div>
and my plugin is called using:
<script>
$('document').ready(function() {
$('.bbcode').bbcode();
});
</script>
and the plugin itself, I am just trying to get the basics done at the minute to update the textbox data when a button is clicked:
(function($) {
"use strict";
$.fn.bbcode = function() {
this.click(function() {
var rel = $(this).attr('rel');
if (rel == 'editor') {
return this;
} else {
alert($(this).attr('rel')); // I can see this pop up so the click event is firing
$('.bbcode[rel=editor]').val('test');
return this;
}
});
}
} (jQuery));
This seems to be the only way I can pick up the textbox, I don't really want to hardcode the class I want like that. I think what I am looking for is a way to get the collection from the function call in the script tags.
This is more than likely something stupid/obvious I have overlooked.
The value of this in the immediate function refers to the collection. However, it is shadowed by the this inside your click handler (which refers to the element being clicked) so you cannot access it.
Create a variable to store this and that'll be your collection.
(function ($) {
"use strict";
$.fn.bbcode = function () {
var $editors = this;
this.click(function () {
var rel = $(this).attr('rel');
if (rel == 'editor') {
return this;
} else {
alert($(this).attr('rel')); // I can see this pop up so the click event is firing
$editors.val('test');
return this;
}
});
}
}(jQuery));

How to create a reference to an anonymouse addEventListener handler?

function alertString(str) {
alert(str);
}
var str = "hello";
var alert_string = document.getElementById("alert_str");
// this can be removed with removeEventListener
// alert_str.addEventListener("click", alertString, false);
// but since I need to pass an argument
// alertString is wrapped within an anonymouse function
alert_string.addEventListener("click", function() {
alertString(str);
}, false);
document.getElementById("remove_alert").onclick = function() {
alert_string.removeEventListener("click", alertString, false);
};
<input type="button" id="alert_str" value="alert" />
<input type="button" id="remove_alert" value="remove alert" />
The click event handler cannot be removed since it is wrapped inside an anonymouse function.
How can I create a reference to that function so I can remove alertString from the alert button?
Quickest, simplest method:
function alertStringWrapper() {
alertString(str);
}
alert_string.addEventListener("click", alertStringWrapper, false);

Categories

Resources