$(document).on() in plain JavaScript? - javascript

In jQuery there is .on() which can be used as:
$(document).on('click', '.foo', function() { /* ... */ });
This listens for click events on all DOM elements with the class .foo.
However, this also listens for any eventual elements added to the DOM later, so it is not equal to:
var elements = document.getElementsByClassName('foo');
for (var element in elements) {
element.addEventListener('click', function() { /* ... */ });
}
How do I do this in plain JavaScript? Am I supposed to use a MutationObserver? If so, then how? If not, then what?

That called event delegation, in the pure javascript you could attach the click event to the parent element then on click check if the clicked element match the target you want to click and perform the action you want ,like the example below :
document.getElementById("parent-item").addEventListener("click", function(e) {
// e.target is the clicked element!
// If it was an item with class 'foo'
if(e.target && e.target.className == "foo") {
console.log("foo "+e.target.innerText+" was clicked!");
}
});
Hope this helps.
document.getElementById("parent-item").innerHTML += "<li class='foo'>Item 3</li>";
document.getElementById("parent-item").addEventListener("click", function(e) {
if(e.target && e.target.className == "foo") {
console.log("foo "+e.target.innerText+" was clicked!");
}
});
<ul id="parent-item">
<li class='foo'>Item 1</li>
<li class='foo'>Item 2</li>
</ul>

Related

Jquery .append() appends on every event

I have very minimal javascript and jquery knowledge, so the problem is, when click with mouse "li" tab and press ENTER jquery attach .append() on every mouse click event.
$(document).on("click", function(event){
let $ul_elem = $(event.target).parent().parent();
const $li = '<li><input type="text" name="geras"></li>'
if($(event.target).parent().prop("localName")=="li"){
console.log($(this.event))
$(window).on("keydown", function(event){
if(event.keyCode == 13) {
event.preventDefault();
$($ul_elem).append($li);
$($ul_elem).children().last().children().focus();
return false
}
})
}
else{
$(window).unbind("keydown");
}
})
in result if i click like 5 times with my mouse on the same li tab, it will create 5 new const $li elements and i dont want that.
You should avoid binding event handlers in context of another event handler. Your code currently rebinds the keydown handler on each click (when the if statements succeeds.) This is why the code appends several elements on each Enter. I guess you want to append li elements to ul elements conditionally. If yes this is one way of doing it:
$(document).on("click", "ul", function() {
$(this).toggleClass('active');
});
$(window).on("keydown", 'ul.active', function(event) {
if (event.keyCode == 13) {
const $ul_elem = $(this);
const li = '<li><input type="text" name="geras"></li>'
event.preventDefault();
$ul_elem.append(li);
$ul_elem.children().last().children().focus();
return false
}
})
This makes the keydown handler work conditionally by using event delegation. In case you want to listen to the keydown event of input elements you can just code $(document).on("keydown", 'input[type=text]', function(event) { ... and there is no need to use click handler. I'm still not sure what you are trying to achieve though.
what I want to do is after i put text in my default li > input field and press ENTER i want to create new li in ul
This should do it:
$(document).on("keyup", 'li input[type=text]', function(event) {
if (event.keyCode == 13) {
const $ul_elem = $(this).closest('ul');
const li = '<li><input type="text" name="geras"></li>'
event.preventDefault();
$ul_elem.append(li);
$ul_elem.children().last().children().focus();
}
})

Finding the text inside this element

I'm looking to make a fairly simple operation: you click on an li, you get the text inside, using JavaScript (not JQuery). What I can't figure out (or find out) is how to get the innerHTML.
function enable() {
document.addEventListener('click', e => {
if (e.target.classList.contains('refine-menu-li')) {
var selected = this.innerHTML;
console.log('stuff'); // Working
console.log(selected); // Not working
}
});
}
Is the problem that I am using class and so require a for-loop? Or is this a foolish thing to try and use?
Thanks!
You could try something like this, without using an arrow function:
document.getElementById("js-list")
.addEventListener("click",function(e) {
if(e.target && e.target.nodeName == "LI") {
console.log(e.target.innerHTML);
}
});
<ul id="js-list">
<li>value1</li>
<li>value2</li>
<li>value3</li>
</ul>
Arrow functions capture this from the context they are declared in.
this.innerHTML is not the innerHTML you are looking for.
You probably want e.target.innerHTML.
If you weren't using an arrow function, then this will wouldn't be the value you wanted. Event handlers are called in the context of the element they are bound to (document in this case), not the element that triggered the event.
Try this
function enable() {
document.addEventListener('click', e => {
var current = e.target;
if (e.target.classList.contains('refine-menu-li')) {
var selected = current.innerHTML;
console.log('stuff'); // Working
console.log(selected); // Not working
}
});
}
enable();
<ul>
<li class='refine-menu-li a'>1 </li>
<li class='refine-menu-li b '>2</li>
<li class='refine-menu-li c '>3</li>
<li class='refine-menu-li d'>4</li>
</ul>

Stop propagation of event from child to parent and inbetween ones

Sorry the title maybe a bit bogus. but here its, imagine I have 3 divs like this :
<div id="1" class="clickable">
<div id="2" class="some random thing">
<div id="3" class="clickable">
</div>
</div>
</div>
now imagine I have
$('.clickable').on('click',function(){blahblah});
I want them both to be clickable but not at the same time.
When I click the inside clickable class div (where the id is 3) both the the inner one and the parent one will trigger the blahblah. I know I can use something like
$('.clickable').on('click',function(e){e.stopPropagation(); blahblah});
but the problem is even if I do that, clicking the middle child (the one with the id of 2) will trigger the blah blah on the parent as well.
Is there anyway to stop that? For example if this div and only this div not parent not child, only this div has the class of clickable, be clickable.
Thank you very much.
event.stopPropogation stops the event from bubbling up the event chain, but this conflicts when you click on the middle div. I am posting the javascript code that you can refer to. Inside the click event listener, the conditional if block checks whether the event was triggered in that particular div element, hence stopping the event bubbling.
document.getElementById("outer").addEventListener('click', function(event) {
if (event.target !== this) {
return;
}
alert("You clicked outer div!");
});
document.getElementById("middle").addEventListener('click', function(event) {
if (event.target !== this) {
return;
}
alert("You clicked middle div!");
});
document.getElementById("inner").addEventListener('click', function(event) {
alert("You clicked inner div!");
});
You can also refer to this fiddle : https://jsfiddle.net/9fskuunr/3/
You might want to do something like this
$(".clickable").click(function(e){
e.stopPropagation();
var id = $(e.target).attr('id');
alert(id + ' is clicked');
}).children(':not(.clickable)').click(function(e) {
return false;
});
See the JSFiddle here: https://jsfiddle.net/3h4yvfv4/1/
One approach you might want to consider is to use event delegation. That way you only assign one event handler, rather than multiple event handlers for every .clickable element, which may give you a performance benefit depending on how many .clickable elements you have on a given page.
The code using event delegation looks something like this:
$(document).on('click', function(e) {
var target = $(e.target),
isClickable,
closestClickable,
isNestedInClickable;
isClickable = target.hasClass('clickable');
if (isClickable) {
handleClick(e);
} else {
closestClickable = target.closest('.clickable');
isNestedInClickable = !!closestClickable;
}
if (isClickable || isNestedInClickable) {
e.stopPropagation();
}
});
function handleClick(e) {
console.log(e.target.id + ' clicked');
}
JSFiddle: https://jsfiddle.net/sytkvgng/2/

How to select next matched child-item in an ul and trigger a click event

Can anyone help me with this problem:
I want to trigger a click event on the next href nested inside an unordered list on an keyup-event but I can't get it running.
The HTML looks like this:
<ul>
<li>Start</li>
<li>Topic 1</li>
<li>Topic 2</li>
<li>Topic 3</li>
</ul>
and the jQuery looks like this:
$(document).keyup(function (e) {
if (e.keyCode == 40) { // down
$('#active').next("li a").click();
}
});
You are trying to select the succeeding li sibling element of the a#active element. It doesn't have an li sibling elements, but its parent element does.
You need to select the parent, and then select the sibling li element from there.
$(document).keyup(function(e) {
if (e.keyCode === 40) { // down
$('#active').parent().next().find('a').click();
}
});
You could also use the .closest() method, if the nesting varies:
$(document).keyup(function(e) {
if (e.keyCode === 40) { // down
$('#active').closest('li').next().find('a').click();
}
});
You may actually have to access the first matched DOM element in order to fire the click event as well (since .click() is a native DOM element method), so you could also try:
$(document).keyup(function(e) {
if (e.keyCode === 40) { // down
$('#active').closest('li').next().find('a')[0].click();
}
});

How To Make Link on Parent Node Active in Tree View?

I want to make link on parent node active in tree view. So far I do this:
<li>A - Referensi Spasial <!--this is parent node-->
<ul>
<li>Jaring Kerangka Referensi Geodesi</li>
<li>Model Geoid
<ul>
<li>AB01010010</li>
<li>AB01010020</li>
</ul>
</li>
<li>Stasiun Pasang Surut</li>
</ul>
</li>
When I click the parent node, it just expand the children nodes. What I want is when I click it, it open the link I set on <a></a>
Here is my screenshot of my tree view:
And this is the javascript code:
$.fn.extend({
treed: function (o) {
var openedClass = 'glyphicon-minus-sign';
var closedClass = 'glyphicon-plus-sign';
if (typeof o != 'undefined'){
if (typeof o.openedClass != 'undefined'){
openedClass = o.openedClass;
}
if (typeof o.closedClass != 'undefined'){
closedClass = o.closedClass;
}
};
//initialize each of the top levels
var tree = $(this);
tree.addClass("tree");
tree.find('li').has("ul").each(function () {
var branch = $(this); //li with children ul
branch.prepend("<i class='indicator glyphicon " + closedClass + "'></i>");
branch.addClass('branch');
branch.on('click', function (e) {
if (this == e.target) {
var icon = $(this).children('i:first');
icon.toggleClass(openedClass + " " + closedClass);
$(this).children().children().toggle();
}
})
branch.children().children().toggle();
});
//fire event from the dynamically added icon
tree.find('.branch .indicator').each(function(){
$(this).on('click', function () {
$(this).closest('li').click();
});
});
//fire event to open branch if the li contains an anchor instead of text
tree.find('.branch>a').each(function () {
$(this).on('click', function (e) {
$(this).closest('li').click();
e.preventDefault();
});
});
//fire event to open branch if the li contains a button instead of text
tree.find('.branch>button').each(function () {
$(this).on('click', function (e) {
$(this).closest('li').click();
e.preventDefault();
});
});
}
});
//Initialization of treeviews
$('#tree1').treed();
So, how can I do that thing? Can anyone help me? Thanks
If my understanding is correct, you are asking why your links seem to have no effect at all, and clicking on them just expands the tree as if it were normal text?
It seems to me that this is simply due to the code that attaches events on those links, i.e. the block below comment "fire event to open branch if the li contains an anchor instead of text".
The $(this).closest('li').click(); instruction generates a new click event on the parent "li" item.
The e.preventDefault(); instruction prevents the link from receiving the "click" event, therefore it does not redirect the page / scroll to anchor.
So the result is as if the "click" had "jumped" your link and be passed to the parent "li", therefore not redirecting but expanding the tree.
You could simply remove that block to restore the links normal behaviour. However, the "click" event would still bubble to the parent "li" element, and expand the tree. Not an issue if the pages is redirected, but it is noticeable if the link goes to a local anchor (same page).
To prevent this (but still let the link do its normal job), keep the block but replace the 2 inner instructions by e.stopPropagation();. On the contrary of preventDefault(), it lets the current event happening, but it stops the event bubbling (parent elements do not receive it).
Now I am not sure about the reason for that block. It seems that it was more intended for anchors (which use the same "a" tag but with "name" attribute instead of "href"). But there would be no reason to prevent the "click" event on an anchor?

Categories

Resources