Javascript- Cancel parent elements onmouseup event? - javascript

So I have a parent that defines a onmouseup event that hide/display a table. The problem is that I want the ability to have nested expandable/collapsible tables but when I click one that is nested it will fire the event for the parent and collapse everything. I can do some niffy stuffy in javascript like assume that the nested event will fire first and then cancel the parent event but that seems kind of hacky. Is there a way to declare from a child element that no parent elements should fire for this event?

I don't think you can declare that kind of thing on an element
but you could, as you implied, try inside the handler of the child:
e.stopPropagation()
where e is the event ? or return false; should have the same effect, but I seem to remember having an issue (perhaps IE where it didn't work, but that could just be another factor I was missing)

Could you possibly iterate through all the parents and re-define their onMouseUp property to do nothing?

Related

How to use JQuery.find() when DOM is dynamic

I have a cascading menu with the following flow;
click on an item from menu-1
creates and updates menu-2 li elements
click on an item from menu-2
creates and updates menu-3 li elements
etc..
```
$firstMenu = $('.prime-menu');
$secondtMenu = $('.second-menu');
$thirdMenu = $('.third-menu');
```
As i'm traversing through different elems. within each menu, using find() comes as a blessing, the issue is that the script loads when no menu other than the first menu is created so $secondtMenu.find('.item-year').click(function (clickEvent) {}) is 0 length.
What are my options in JQuery to make my find() functions work on elements that are not loaded yet in the DOM?
I thought of creating an event listener, but I think there are more terse approaches than that.
You should use delegates when dealing with dynamic HTML. For instance, use an outer element like document or body to "start" your finds.
$(document).find(".prime-menu");
EDIT: Find and event delegation
The solution was to use find with event delegation. Example event.
$(document).find(".prime-menu").on('mouseenter', '.track-table tbody tr', function(){ });
You state that when you click on an item from menu-1 it creates and updates menu-2 li elements. In this function is where you should do your event binding. The DOMElement will exist in js before being added to the dom, and that is where your bindings should be set.
If you need help share this code with us I'm sure myself or someone will be able to help you sort it out.
Bind the click handler to the menu parent, not the actual menu items.
Something like this might work...
$("#menuparent").on("click",".item-year",function(event) {
var clicked_element = event.currentTarget;
});
Doing it this way, even if the element with class .item-year is added to the dom after the click event is bound, it will still register the click.

Is using a universal document.addEventListener("click",f) listener slower or weaker form than a specific use of it?

My code is this:
document.addEventListener('click', function(ev){
if(ev.path[0].className == 'linkTogether'){//do something}
if(ev.path[0].id == "createNewPage"){//do something}
});
Which has actually been working well for dynamically created buttons and nodes, but something just feels off about it. So I'm wondering if this is best practice or if there is a better way to add event listeners to dynamically created elements.
Thanks,
Jack
In specific cases where you have huge amount of objects that behave in the same way you can use this technique (adding event listener to their parent) to improve the performance of your script.
In a general page however you just have to many different objects and iterating trough all of them to check which one you've clicked is not faster.
Here is an article for the technique you are referring to - event delegation.
This is the proper pattern for creating event listeners that will work for dynamically-added elements. It's essentially the same approach as used by jQuery's event delegation methods (e.g. .on).
However, it does have performance implications. Every time you click anywhere in the document, the code will run, and have to go through the entire list of event bindings that you need to check. You can improve this by adding your event listener to a more specific element. If the dynamic elements are always added inside a specific DIV, add your listener to that DIV rather than document.
This also avoids another pitfall of event delegation. Event delegation depends on the event bubbling up from an inner element to all its containers. But if there are any handlers along the way that call event.stopPropagation, the event won't make it out to document. If you add the listener to a lower element, you're less likely to have a conflict like that.
And I would like to add, if you create elements dynamically, better you include the listeners inline and filter in the function what you want to do.
<div class="form_ID1" onclick="myfunction(this, event);">
... children bubbling
... Use if statements in caught js myFunction function.
In myfunction function you will capture the child element by event.target and the element that contains the listener by this.className.
There are scenarios however that you need a universal ( document ) click event. e.g You need to close a pop up when you click outside of a pop up !! It is like: e.g.
if (clicked.className != popup.className) popup.remove()
Even in this case there is a workaround by inserting an onblur="myfunction(this); in the parent DIV of the popup.

Adding an event listener to a div to perform an event if the div becomes empty (has no children)

My goal is the following: create a listener that will be bound to a div and it will fire up if there are no children left in that div.
I keep seeing how to bind a listener to say onClick etc.. but I cannot seem to find anyone that deals with actual states of the elements (empty, at least one child, etc... ). I have not started coding anything yet because I am not sure what kind of approach I need to take, since I am pretty new to JavaScript development. I am not necessarily looking for an answer with code in it but more of an advise on what approach to take.
One of the approaches that I was thinking of was to simply have a function call every single time I make a change to the div such as deleting a child but that seems too trivial. I want to create some kind of automation in that process of checking for no children.
jQuery has remove event fired when element is removed
$(el).on("remove", function () {
alert("Element was removed");
});
You could use live (if they are appended dynamically to parent container) or on (if statically) method to bind this event to child nodes of particular container and on every remove event check if parent container has any child nodes. If not then do some actions.
You cannot assign a listener to a div element to check if the element has no children(done automatically without knowing which function is removing the children, but only knows that there was a child removed). Granted you could do a function to check every so many seconds but that is not what I wanted. Anyways, where I remove the children, I simply added a function that checks if the parent is left with no children and it handles it there.

Binding event to the element in JavaScript

Generally, when I want to bind some event to an element, I will bind the event to the element directly. For example, I want to bind the click event to the "li" element:
<ul id="ul_list">
<li class="t">xxxx</li>
<li class="t">xxxx</li>
.....
</ul>
var lis=document.getElementById("ul_list").children();
for(var i=0;i<lis.length;i++){
lis[i].onclick=function(){
console.info(this.innerHTML);
}
}
It works.
But in some open source code, I find that people prefer to bind the event to the parent element:
document.onclick=function(e){
e=e==null?:window.event:e;
var target=e.target; //the browser is not considered here
if(target.className=='t' && target.localName='LI'){
console.info(target.innerHTML);
}
}
I wonder which is better?
Also, when handling drag events, people bind the mousemove event to the whole document. Why?
people prefer to bind the event to the parent element
This is referred to as event delegation and is especially useful when you want to trigger the same event handler for multiple elements. Instead of binding an event handler to each those elements, you bind it to a common ancestor and then check from which element the event originated. This works, because events bubble up the DOM tree.
I wonder which is better?
It depends, both approaches have their pros and cons.
Event delegation can be slower, as the event has to bubble up first. You also might have to perform DOM traversal because the event might not originate at the element you test for. For instance, in your example, the li elements might have other children, lets say an a element. To find out whether the clicked a element is a descendant of one of the lis, you have to traverse the ancestors and test them.
On the other hand, binding the handler directly is faster in the sense that the event is processed directly at the element. But if you bind a lot of event handlers and don't do it properly (like in your example) you use more memory than you actually need. Older browsers (I think especially IE) might also perform worse if there are many event handlers.
Also,sometime when handle the drag effect,people always bind the mousemove event to the whole document,why?
The problem is that while dragging an element, the mouse often moves faster than the element and leaves it. If you bind the mousemove event only to the dragged element, whenever the cursor leaves the element, the movement would stop. To avoid this, the event handler is bound to the whole document (for the duration of the dragging) so that the movement is smoothly.
Linking to the parent means you are adding one event handler instead of multiple. That is a boost for performance in your application! Also if you add new elements to the page, you do not have to worry about binding them.
Only time when that model is a bad design is when you need to cancel the event. For example, you have links in the li and you need to prevent them from doing their default action.
In case of click event, it's better to bind directly to the affected elements, no point binding to everything - why do you need to have your function trigger when you click something that is totally not relevant to you?
It can be useful when the elements are spread over the document and hard to "collect" them, e.g. when they only have the same class - getElementsByClassName is not very efficient in pure JavaScript as you need to iterate over all the elements, so in such case it's better to trigger the function always and check what has been clicked.
Bind handlers to the most specific event and element possible.
Note that (just to be pedantic!) you bind a handler to an event for an element, not 'bind some event to an element'.

can I programmatically examine and modify Javascript event handlers on html elements?

I am doing browser automation using C#, and I would like to modify or possibly just eliminate event handlers on some of the html elements in webpages that I am looking at. E.g., suppose there is a button there which might (or might not) have an attached onClick event. How do I go about:
- finding out if there are any event handlers attached to onClick for it?
- removing them?
Replacing element with its own clone should effectively discard all of its event listeners (well, technically listeners are still on an element, but since an element is replaced with its own clone, it looks as if listeners were simply removed):
el.parentNode.replaceChild(el.cloneNode(true), el);
Unfortunately, this won't work in IE, since IE erroneously transfers event listeners of an element on clone. To work around that you can reassign innerHTML of element's parentNode:
el.parentNode.innerHTML = el.parentNode.innerHTML;
Note that this will not only remove event listeners of an element, but also listeners of all of element's siblings.
Alternatively, you can work around IE issue by reassigning outerHTML of an element:
el.outerHTML = el.outerHTML;
This depends on how the event handlers have been attached to the element.
If they are attached using addEventListener or one of the proprietary addWhatever listener methods, there is no way to list them.
If they are attached by modifying the event property, ie. node.onclick = whatever, then you can read the value of the property to get the function and it'll work the same as any other JS func.
There is a third way too:
You can override the default addEventHandler/addListener behavior if the code you automate uses those. By doing this, you can replace the default behavior by one which pushes each handler into an array, which you can then loop over yourself.
The following code might work:
var oldAddEventListener = HTMLElement.prototype.addEventListener;
HTMLElement.prototype.addEventListener = function(event, handler, bubbling) {
/* do whatever you want with event parameters */
oldAddEventListener.call(this, event, handler, bubbling);
}
As far as I know, it's not currently possible to use javascript to get all the event handlers attached to an element.
See this link for more info:
http://www.howtocreate.co.uk/tutorials/javascript/domevents

Categories

Resources