How to implement event delegation in React - javascript

I need to disable copy and contextmenu for a subset of elements in my app (I know it's easy to bypass, but it's a requirement I need to meet).
In vanilla JS, I achieve this by having a unique classname (eg - no-select), and attach the copy/contextmenu events to the document, then test that target element for that classname.
I was wondering if there was a standard way to implement class-based event delegation with React, or should I just do this outside of the React realm.
The main benefits for me for doing this within the React realm are:
I don't need to care about cleanup.
Since this is a localized requirement, doing this for the entire document seems like an overkill.
Would rather not have side-methods for doing things.

Related

Alternative to Falsely Triggering an Event

TLDR Below
JS Fiddle To Demo
I've been really involved in recreating the tools that are foundations of premiere JS Libraries to better improve my skills. Currently I'm working on functional data-binding a la Angular.
The idea of data-binding is to take data and bind it to elements so that if manipulated all elements subscribed will change accordingly. I've gotten it to work but one thing I hadn't considered going into it was the issue with innerHTML vs value. Depending on the element you need to change one or the other( in the demo above you'll see that I needed to specifically single out the button element in a conditional statement because it has both, but that's kind of a fringe case )
The issue is that in order to capture a SPAN tag update I needed to trigger an event to happen, and the easiest one to manipulate for Text Boxes/Textareas was 'keyup'.
In my function then, if you pass in an element with no value property we assume you're going to be updating innerHTML, and we setup an observer to determine if the element ever mutates, and if it ever does, the observer will emit a 'keyup' event.
if (watchee.value == void(0)) {
var keyUpEvent = new Event('keyup');
var observer = new MutationObserver(function(mutations) {
mutations.forEach(function(mutation) {
watchee.dispatchEvent(keyUpEvent);
});
});
observer.observe(watchee, {
childList: true
});
}
Now it may just be my paranoia, but it seems like I might be tunneling into a can of worms by faking 'keyup' on an element that doesn't natively have that support.
TLDR:
I'm curious if there's an alternative way to make, a.e. a span tag reactive other than faking a 'keyup'/'keydown'/'change' event? For instance, is there a way that I can make my own pure event(by pure I mean not reliant on other events) that checks if innerHTML or value has changed and then performs a function? I know that this is probably possible with a timer, but I feel like that might hinder performance.
EDIT: just an aside. In the demo the function called hookFrom works by taking a DOM node and returning a function that will take the receiving dom node and continues to return a function that will take additional receiving dom nodes. :
hookFrom(sender)(receiver);
hookFrom(sender)(receiver)(receiver2);
hookFrom(sender)(receiver)(receiver2)(receiver3)(receiver4)...(receiver999)...etc
JS Fiddle To Demo (same as above)
There is nothing inherently wrong with creating a similar event on a DOM node that doesn't natively have that functionality. In fact this happens in a lot of cases when trying to polyfill functionality for separate browsers and platforms.
The only issue with doing this sort of DOM magic is that it can cause redundancy in other events. For instance the example given in this article: https://davidwalsh.name/dont-trigger-real-event-names shows how a newly minted event using the same event name can cause problems.
The advice is useful, but negligible in this specific case. The code adds the same functionality between text boxes, divs, spans, etc... and they are all intentionally handled the same way, and if the event would bubble up to another event, it would be intentional and planned.
In short: There is a can of worms that one can tunnel into while faking already explicitly defined event names, but in this case, the code is fine!

Pushing event handlers to parent components

If, for example, I have a spreadsheet and want to attach handlers to cells to handle a users interaction. Typically, you would attach the handlers to the cell component itself. But if you are creating thousands of cells, this seems rather inefficient.
If I had a component hierarchy where SheetComponent -> CellComponents how can I attach a single handler to SheetComponent to handle each cell interaction? When the user interacts, I would like to have access to CellComponents props in order to identify which was clicked.
DOM events, when using React are synthetic ... they are all handled at the document level and then synthesized across all handlers. So, for DOM events, a handler hasn't been attached to each element for each event. However, that still means there is overhead that can't be avoided as your components would need to be notified that an event has occurred.
For communicating to the SheetComponent from a CellComponent, you could simply add your own event as a property: onCellActivated for example. If you have more than a couple, you could, instead of having lots of events needing to be wired up, you could have a generic event with an argument set to the type of event:
onCellEvent({ eventType: 'activation', cell: this })
That pattern starts to look more like an Action Creator/Action following the Flux pattern (without the Dispatcher and Store of course).
Instead of relying on your own events, you could use a Flux/Action/Dispatcher pattern potentially to relay key events to a centralized location (like the SheetComponent) and from there handle the interaction. With the action dispatched, you would include the key information about the cell where the interaction took place.
But, you might want to test the performance of a more traditional event model first as this might add extra complexity with little actual benefit.
You might also want to take some inspiration from Facebook's Fixed Data Table component, written for React. It's designed to handle thousands of rows of data efficiently.

Lateral communication in Polymer

Here is the problem:
Any two Polymer elements may need to communicate. No assumption is made as to where these elements might be in the DOM (or shadow DOM), this means one event cannot simply bubble up to another element.
The good old way to achieve this would have been to let events bubble up to the root node and then fire broadcast events on the root node for other elements to listen to.
This approach however breaks encapsulation and seems to go against Polymer's overall design. AngularJS for example provides an event broadcaster that keeps controllers from unnecessarily keeping references to the root node.
Can such approach be achieved with Polymer? Otherwise can this be solved with a different approach?
You should be able to do this using polymer-signals
http://www.polymer-project.org/articles/communication.html#using-ltpolymer-signalsgt
Quoting from the doc:
Your element fires polymer-signal and names the signal in its payload:
this.fire('polymer-signal', {name: "foo", data: "Foo!"});
This event bubbles up to document where a handler constructs and dispatches a new event, polymer-signal-foo, to all instances of . Parts of your app or other Polymer elements can declare a element to catch the named signal:
<polymer-signals on-polymer-signal-foo="{{fooSignal}}"></polymer-signals>

Having a single event listener for custom events generated by any element in the page

I am in the process of creating a huge web application, with a JavaScript based UI, and many events generated continuously.
To avoid bad performance due to the huge amount of the event listeners needed, I of course opted to use a single event listener which will catch all the events generated from the children elements (event bubbling).
The problem is, this application is designed in such a way that one or more modules can be loaded into the main JavaScript library I'm coding (which is responsible for controlling the UI and every other aspect of the program). Of course every module should be completely independent from each other, so you can choose which methods to load, without affecting the general functionality of the library, only adding or removing features.
Since every module can operate in different DOM elements, I need to have at least a single event listener for each module, since two modules can listen for events generated by html elements placed in different DOM branches.
http://jsfiddle.net/YRejF/2/
In this fiddle for example, the first button will let the first paragraph trigger an event, and its parent will catch it. The second button will let the second paragraph fire the event, but the div listening for the same event won't catch it, because it's not fired from one of its sons.
So my question is: is it possible to have a single event listener, able to listen also to events triggered from elements that are not its sons (elements placed everywhere on the page)?
I was thinking about having a js object, or a dom node, which store the data of the element which triggered the event, and the event itself, then a general event will be fired on the global event listener (no matter where it's placed in the dom), and it will then read the data to discover which element generated which event, and act accordingly.
Any help or suggestion about better ways of achieving this?
jQuery has a special binder for this kind of cases: live(). It let's all events bubble to the document and then handles them accordingly. However, if you use div or other containers for different panels etc, maybe using delegate() makes more sense. Don't worry too much about the number of bound elements. Believe me, it will run as well with 50 binds or 10 delegates as it will with 1 live.

How to keyboard down or up between dropdown "options"?

I have a custom built ajax [div] based dynamic dropdown.
I have an [input] box which; onkeyup, runs an Ajax search which returns results in divs and are drawn back in using innerHTML. These divs all have highlights onmouseover so, a typical successful search yields the following structure (pardon the semi-code):
[input]
[div id=results] //this gets overwritten contantly by my AJAX function
[div id=result1 onmouseover=highlight onclick=input.value=result1]
[div id=result2 onmouseover=highlight onclick=input.value=result2]
[div id=result2 onmouseover=highlight onclick=input.value=result2]
[/div]
It works.
However, I'm missing the important functions behind regular HTML elements. I can't keyboard down or up between "options".
I know javascript handles keyboard events but; I haven't been able to find a good guide. (Of course, the follow-up question will end up being: can I use <ENTER> to trigger that onclick event?)
What you need to do is attach event listeners to the div with id="results". You can do this by adding onkeyup, onkeydown, etc. attributes to the div when you create it or you can attach these using JavaScript.
My recommendation would be that you use an AJAX library like YUI, jQuery, Prototype, etc. for two reasons:
It sounds like you are trying to create an Auto Complete control which is something most AJAX libaries should provide. If you can use an existing component you'll save yourself a lot of time.
Even if you don't want to use the control provided by a library, all libraries provide event libraries that help to hide the differences between the event APIs provided by different browsers.
Forget addEvent, use Yahoo!’s Event Utility provides a good summary of what an event library should provide for you. I'm pretty sure that the event libraries provided by jQuery, Prototype, et. al. provide similar features.
If that article goes over your head have a look at this documentation first and then re-read the original article (I found the article made much more sense after I'd used the event library).
A couple of other things:
Using JavaScript gives you much more control than writing onkeyup etc. attributes into your HTML. Unless you want to do something really simple I would use JavaScript.
If you write your own code to handle keyboard events a good key code reference is really handy.
Off the top of my head, I would think that you'd need to maintain some form of a data structure in the JavaScript that reflects the items in the current dropdown list. You'd also need a reference to the currently active/selected item.
Each time keyup or keydown is fired, update the reference to the active/selected item in the data structure. To provide highlighting information on the UI, add or remove a class name that is styled via CSS based on if the item is active/selected or not.
Also, this isn't a biggy, but innerHTML is not really standard (look into createTextNode(), createElement(), and appendChild() for standard ways of creating data). You may also want to see about attaching event handlers in the JavaScript rather than doing so in an HTML attribute.

Categories

Resources