How do we tell react-rnd to pass an onClick event, sometimes it does, sometimes not - onclick

We have created containers that seem to be the same. We've added RnD to each. There is a close-icon in the upper right of each, with onClick attached. When I look at the Chrome Event Listeners, in some containers RnD passes a click through to our close icon, and in other containers it does not. We get the mousedown for both containers. RnD seems to be adding its classes the same on both. On the containers that do not work, doubleclick also doesn't come through either. Z-index doesn't matter. Does anyone have a suggestion on how to debug why some of the containers are working and others are not?

It seems that this has to do with propagation of the mouse up and down events. By putting a new wrapper that stops propagation, all the divs work well.
const PreserveFocusWrapper = ({ children }) => (
<div
onMouseDown={(event) => { event.stopPropagation() }}
onMouseUp={(event) => { event.stopPropagation() }}
>
{ children }
</div>
)
export default PreserveFocusWrapper
Apparently without this, the close icon (as a child) was not being passed the onClick or onMouseUp events.

Related

How to Attach Events to Table Checkboxes in Material Design Lite

When you create a MDL table, one of the options is to apply the class 'mdl-data-table--selectable'. When MDL renders the table an extra column is inserted to the left of your specified columns which contains checkboxes which allow you to select specific rows for actions. For my application, I need to be able to process some JavaScript when a person checks or unchecks a box. So far I have been unable to do this.
The problem is that you don't directly specify the checkbox controls, they are inserted when MDL upgrades the entire table. With other MDL components, for instance a button, I can put an onclick event on the button itself as I'm specifying it with an HTML button tag.
Attempts to put the onclick on the various container objects and spans created to render the checkboxes has been unsuccessful. The events I attach don't seem to fire. The closest I've come is attaching events to the TR and then iterating through the checkboxes to assess their state.
Here's the markup generated by MDL for a single checkbox cell:
<td>
<label class="mdl-checkbox mdl-js-checkbox mdl-js-ripple-effect mdl-data-table__select mdl-js-ripple-effect--ignore-events is-upgraded" data-upgraded=",MaterialCheckbox">
<input type="checkbox" class="mdl-checkbox__input">
<span class="mdl-checkbox__focus-helper"></span>
<span class="mdl-checkbox__box-outline">
<span class="mdl-checkbox__tick-outline"></span>
</span>
<span class="mdl-checkbox__ripple-container mdl-js-ripple-effect mdl-ripple--center">
<span class="mdl-ripple"></span>
</span>
</label>
</td>
None of this markup was specified by me, thus I can't simply add an onclick attribute to a tag.
If there an event chain I can hook into? I want to do it the way the coders intended.
It's not the nicest piece of code, but then again, MDL is not the nicest library out there. Actually, it's pretty ugly.
That aside, about my code now: the code will bind on a click event on document root that originated from an element with class mdl-checkbox.
The first problem: the event triggers twice. For that I used a piece of code from Underscore.js / David Walsh that will debounce the function call on click (if the function executes more than once in a 250ms interval, it will only be called once).
The second problem: the click events happens before the MDL updates the is-checked class of the select box, but we can asume the click changed the state of the checkbox since last time, so negating the hasClass on click is a pretty safe bet in determining the checked state in most cases.
function debounce(func, wait, immediate) {
var timeout;
return function() {
var context = this, args = arguments;
var later = function() {
timeout = null;
if (!immediate) func.apply(context, args);
};
var callNow = immediate && !timeout;
clearTimeout(timeout);
timeout = setTimeout(later, wait);
if (callNow) func.apply(context, args);
};
}
$(document).on("click", ".mdl-checkbox", debounce(function (e) {
var isChecked = !$(this).hasClass("is-checked");
console.log(isChecked);
}, 250, true));
Hope it helps ;)
We currently don't have a way directly to figure this out. We are looking into adding events with V1.1 which can be subscribed to at Issue 1210. Remember, just subscribe to the issue using the button on the right hand column. We don't need a bunch of +1's and other unproductive comments flying around.
One way to hack it is to bind an event to the table itself listening to any "change" events. Then you can go up the chain from the event's target to get the table row and then grab the data you need from there.
You could delegate the change event from the containing form.
For example
var form = document.querySelector('form');
form.addEventListener('change', function(e) {
if (!e.target.tagName === 'input' ||
e.target.getAttribute('type') !== 'checkbox') {
return;
}
console.log("checked?" + e.target.checked);
});

Add selectedItemCls to First Item of DataView ExtJS

I have ExtJS Dataview with following template for its Items.
<div class="item-container">
<div class="{itemCls}"></div>
<span class="item-title">{title}</span>
</div>
Now, I have set selectedItemCls config with value item-selected, which is styled accordingly in my stylesheet. When I click on items in dataview, it works fine, and selected item is highlighted. But I want to have first item of my dataview be selected by default (and thus having item-selected class already added to it).
I tried to play around the dataview component in its afterrender event but I couldn't add active class to first item.
Update
Note that I want to maintain that toggle behavior of class, so when dataview is rendered and user clicks on other item, first item (on which tab-selected was added programmatically) is no longer highlighted and clicked item gets tab-selected class.
So far, I tried calling dataview.selModel.select(dataview.Store.getAt(0)) within afterrender event, and surprisingly, it works while debugging (breaking execution in afterrender event and proceeding step-by-step) but it throws Uncaught TypeError: Cannot call method 'addCls' of null if I try it without DevTools open. I believe it is due to event bubbling since select() also fires itemclick and selectionchange events internally (I might be wrong though).
P.S. Using Chrome for debugging.
How to attain this?
Try this:
new Ext.XTemplate(
'<tpl for=".">',
'<div class="item-container {[xindex === 1 ? "item-selected" : ""]}">',
'<div class="{itemCls}"></div>',
'<span class="item-title">{title}</span>',
'</div>'
'</tpl>,
)
You could also try this:
listeners: {
afterrender: function(dv) {
dv.selModel.select(dv.store.getAt(0));
}
}
After hacking around for more than an hour, I found the fix!
When using afterrender event, where DataView is technically not fully rendered on UI, calling select() will fire itemclick event but there's nothing on UI, so it would lead to the TypeError I was getting (I'm still not 100% sure if this is the exact reason for TypeError I got).
So I have two possible fixes for this, where I'd prefer 2nd fix.
Option - 1
Make called to select() deferred by a few Milliseconds.
listeners: {
afterrender: function(dv) {
Ext.defer(function() {
dv.selModel.select(dv.store.getAt(0));
}, 10); // Some small number for delay will do.
}
}
Option - 2 (Recommended)
Use viewready event instead of afterrender.
listeners: {
viewready: function(dv) {
dv.selModel.select(dv.store.getAt(0));
}
}
I've used 2nd option and it works perfectly, however, any better suggestion is welcome.

display:none hover trick on a touchscreen device

I am using a CSS hover trick to clean up my interface. Controls will only be shown when the cursor is hovering inside the element. I'm running into an issue when using the interface on a touch screen device. If the control button is not shown display:none and I touch where it should be, the event is still triggered for the button.
Try this fiddle both in your browser and on a touchscreen device to see what I mean...
http://jsfiddle.net/6PvCn/2/
On a touchscreen device, touch the red square and the alert should fire, without the button even showing up. I tested this on both the desktop Android Emulator and my real Android 2.3 phone.
The effect I'm going for is for the button to first be shown without firing, even if the user touches where the button "is".
I'd rather use a pure CSS solution before resorting to javascript.
Try pointer-events: none; along with display: none;
I just tested it on my real device, and it indeed executes the button's action.
You could maybe try to make the red box an image and change the image to a button by an onclick with Javascript. I would have provided you with some code if I wasn't short on time.
You can't do it with pure CSS, tapping the button will put the button into hover state and fire the click event. Instead you should fire the button off on active.
Here is the solution I came up with... http://jsfiddle.net/6PvCn/7/
On an Android touchscreen (don't know about IOS), the hover event for the hidden element is not fired if it is not shown. So basically I check to see if the element was hovered before it was clicked.
In a nutshell
$(".hidden").hover(function(e) {
if(e.type == "mouseenter") $(this).addClass("hovering");
else $(this).removeClass("hovering");
}).click(function(e) {
if(!$(this).hasClass("hovering") return false;
});
The fiddle explains the more complicated situation I had with form elements and dynamically added content. It provides a general solution as opposed to this element specific one.
I wrote a JS solution for you:
https://codepen.io/anon/pen/bmYROr
The trick is to prevent the button's click event getting fired for the first time the outer div is getting clicked because on touch devices click event has hover effect.
let isTouchDevice = true;
let isHovered = false;
document.getElementById('outer').addEventListener('click', (e) => {
if (isTouchDevice) {
if (!isHovered) {
e.stopPropagation();
}
isHovered = true;
}
}, true);
document.getElementById('outer').addEventListener('mouseleave', (e) => {
if (isTouchDevice) {
isHovered = false;
}
}, true);
document.getElementById('btn').addEventListener('click', () => {
alert("hi");
});

tv.ui.button Only responds to mouseclick on pageload

This tv.ui.button only responds to mouseclick when initially loaded, but then responds to keyboard ENTER or mouseclick after it's been clicked at least once. Do I have something wrong here?
HTML
<div class="tv-button alert-button" id="test-button">Alert button</div>
JS
decorateHandler.addClassHandler('alert-button', function(button) {
goog.events.listen(button, tv.ui.Button.EventType.ACTION,
function() {
alert('Button clicked.');
var elementToFocus = goog.dom.getElement('tab1');
var componentToFocus = tv.ui.getComponentByElement(elementToFocus);
tv.ui.Document.getInstance().setFocusedComponent(componentToFocus);;
});
});
EDIT: it seems this may be a question about javascript, not closure specifically. I'm posting a new question under the appropriate tag
Have you made sure that the button has cursor focus? If not then the "Enter" key event will get handed to the default handler.
Well, I fixed it with a semi hack. i used a $('target').click on the button within $(document).ready, which seems to set the focus as if a click event had actually happened

OnClick event for whole page except a div

I'm working on an own combobox control for ASP.Net which should behave like a selectbox, I'm using a textbox, a button and a div as a selectbox replacement. It works fine and looks like this Image:
My problem now is the Selectbox close behaviour: when clicking anywhere outside the opened selectbox it should close.
So I need something like an onClick event for the whole page which should only fire when my div is open. Any suggest how to do that?
Add a click event handler to document. In the event handler, examine its target (or srcElement in IE) property to check that it isn't your open div or any of its descendants.
Set a click event handler on the document that "closes" the pseudo-combobox. In addition, set a click event handler on the pseudo-combobox's container (the div, in this case) which cancels bubbling of the event. Then any clicks in the div will bubble up only as far as the div before being halted, while clicks anywhere else will bubble all the way up to the document.
This is a much easier option than mucking around traversing the DOM from the event's target upwards to work out where the click came from.
EDIT: if you are setting the div's style to display: none; (or something similar) to hide it, then it doesn't matter if you leave the event handler on the document - hiding it when it's already hidden will have no effect. If you want to be very tidy, then add the event listeners when the div is shown, and remove them when it is hidden; but there's probably no need to bother.
document.onclick = function() {
if(clickedOutsideElement('divTest'))
alert('Outside the element!');
else
alert('Inside the element!');
}
function clickedOutsideElement(elemId) {
var theElem = getEventTarget(window.event);
while(theElem = theElem.offsetParent) {
if(theElem.id == elemId)
return false;
}
return true;
}
function getEventTarget(evt) {
var targ = (evt.target) ? evt.target : evt.srcElement;
if(targ && targ.nodeType == 3)
targ = targ.parentNode;
return targ;
}
Put a transparent div that covers whole the page and lies under your dropdown. At that div's click event hiğde your dropdown.

Resources