How to prevent modal click-through? - javascript

I have a modal that looks something like this:
<div className="modal modal-focuser" tabindex="1" style="z-index: 5;">
<div className="handle-modal-close"></div>
<div className="modal-content modal-content">
<div className="body">
<span>
<div className="container">
<div className="title-text">Title Text</div>
<div className="body-text">Body Text</div>
</div>
<button onClick={this.toggleView} className="toggle-view">Switch View</button>
</span>
</div>
</div>
</div>
With the click code like the following:
toggleView = e => {
e.stopPropagation();
this.setState(prevState => ({ view: !prevState.view}));
}
But for some reason (despite the stop propagation), when I click the button, sometimes the parent's event handlers are still being activated.
That is, there is a table behind the modal with click-able rows, and when I click the Toggle button in the modal, not only is that button clicked, but also the table row behind the behind (which also has its own click event handlers)
The stranger thing is that this only sometimes happens, and only happens on mobile. Try as I might, I can't replicate the behavior on my PC in Chrome or Firefox.
What could be causing this?

You're using the onclick handler, which essentially ignores all the propegation through down-up events. Try using onmousedown. Chances are the thing underneath the modal has a down or up event. Learn about "bubbling" : What is event bubbling and capturing?
<button onMouseDown={this.toggleView} ... yada yada
Using the mousedown will allow you to prevent bubbling through the stopPropegation, and maybe also look into stopImmediatePropegation -- which prevents other listeners of the same type (click, down, up) from getting called: https://developer.mozilla.org/en-US/docs/Web/API/Event/stopImmediatePropagation

Related

Method not called on blur event applied to span element

I would like the following method to be run:
setHeroButtonTextOption(heroButtonText) {
this.builderComponentsService.setPageComponentById(this.componentId, 'heroButtonText', heroButtonText);
}
Each time the user loses focus of the following element:
<div class="builder-components hero-button-click button-outer-container text-center text-md-left mt-5">
<div (click)="selectHeroButton($event, componentId + '-button')"
[attr.data-cy]="'hero-button-container'" [class]="setActiveElement('button')"
[ngClass]="setHeroClass('hero-button')" class="builder-components hero-button-click button-container"
id="{{componentId}}-button" style="display:inline-block">
<button [attr.data-cy]="'hero-button'" [ngStyle]="heroButtonStyle"
class="builder-components hero-button-click btn hero-button">
<span (blur)="removeLineBreaks($event); setHeroButtonTextOption($event.target['innerText']);"
(keydown.enter)="setHeroButtonTextOption($event.target['innerText']); $event.preventDefault()"
[attr.contenteditable]="setContentEditable()" [attr.data-cy]="'hero-button-text'"
[innerText]="heroButtonText" class="builder-components hero-button-click">
</span>
</button>
</div>
</div>
Currently, it isn't happening even though I have a blur event on <span>. How can I fix this?
The blur event will be raised from the button, not the span. If you are trying to include the innerText of the span with the event handler, it looks like it is already bound with heroButtonText, which you can pass as a function argument or reference from the component.
<button (blur)="setHeroButtonTextOption(heroButtonText)">
<span>{{ heroButtonText }}</span>
</button>
Edit - The button should be emitting that blur event. If that isn't working you will need to post more code, it could be that removeLineBreaks($event) is throwing an error, preventing the next call from being made.

HTML element in button prevents disabled in the wrapper element

Fiddle: http://jsfiddle.net/0o1mrapd/20/
Angular stackblitz link: https://stackblitz.com/edit/angular-fhtaki?file=src%2Fapp%2Fapp.component.html
I have a complex case which i need some enlightenment. (For angular developers, you can think the wrapper div as a host selector, <my-button></my-button>)
As you can see in the fiddle I have a disabled button with a wrapper div which has a click event.
<div onclick="alert('hey')" style="display:inline-block">
<button disabled>
<span>Click</span>
</button>
</div>
What I expect is that when I click on that area, nothing will happen but alas I get the alert. If I remove the span element and put plain text inside the button, this works.
<div onclick="alert('hey')" style="display:inline-block">
<button disabled>
Click
</button>
</div>
How can I make the div unclickable in this case? I found out that pointer-events: none does the trick but then I lose the curser-event which I need for accessibility
I stumbled upon this issue while creating a custom button component with an ng-content in Angular but then realized this is bigger than the framework.
Some links i checked:
Can you prevent an Angular component's host click from firing?
Add CSS cursor property when using "pointer-events: none"
How to stop event propagation with inline onclick attribute?
https://github.com/angular/angular/issues/9587
Maybe this example will be useful
function clickHandler() {
console.log('Click');
}
<div onclick="return false;">
<button onclick="clickHandler()">
Click
</button>
</div>
You can use this css property to avoid click event be fired in the span tag. It could be a workaround.
<div onclick="alert('hey')" style="display:inline-block">
<button disabled>
<span style="pointer-events:none;">Click</span>
</button>
</div>

jQuery parent(); function removeClass(); not working (bug)

I have a portfolio where I list portfolio items.
I have classes so when you click the item, it has an effect.
For some reason, when I click the minus button, it doesn't remove the class 'on'.
Here is the jQuery:
$('.portfolio-item').click(function() {
$(this).addClass('on');
});
$('.minus').click(function() {
$(this).closest('.portfolio-item').removeClass('on');
});
and here is the element set up:
<div class="portfolio-item" style="margin-top: 5px; ">
<div class="overlay">
<h1>LOW POLY ISLANDS</h1>
<h3>LOW POLY</h3>
</div>
<div class="about">
<h1>LOW POLY ISLANDS</h1>
<h3>LOW POLY</h3>
<div class="descrip">
This is a low poly island make in Blender and edited in Photoshop.
</div>
<div class="minus"></div>
<div class="plus"></div>
</div>
<img src="https://mir-s3-cdn-cf.behance.net/project_modules/max_1200/57909c29180525.55fc4b1875c26.png" width="100%" />
</div>
How do I fix this - I want to be able to remove the class 'on' when I click on 'minus'.
When you click your minus it removes the class on. However, at the same time, as minus is located within portfolio-item, it triggers its click event and applies this class back.
You can use e.stopPropagation() to disable this behaviour.
According to documentation, e.stopPropagation
prevents the event from bubbling up the DOM tree, preventing any parent handlers from being notified of the event.
Here is the working JSFiddle demo. It looks awful, but demonstrates the functionality.
you need to use e.stopPropagation()
$('.minus').click(function(e) {
e.stopPropagation();
$(this).closest('.portfolio-item').removeClass('on');
});
DEMO

Returning focus, contenteditable misses keypress event

Story
In a custom content editor component (contenteditable div), in which I need to prevent certain character inputs. If the user tries to input a restricted character, a bootstrap modal dialog is shown explaining the restriciton ("You are not allowed to use 'x') and the event is prevented (preventDefault). After dismissing the dialog, the focus goes back to the contenteditable and input can resume.
Issue/Bug?
After dismissing the dialog, the focus is indeed returned to the contenteditable. However, the first key event doesn't trigger keypress on the contenteditable bypassing the keypress event listener.
I tried setting manually the focus and setting the document selection explicitly on the contenteditable, with no luck. I've tried both with jquery and pure js.
Any ideas why is the first event bypassing the keypress listener?
Illustration
JSFiddle here, example restricting "." input:
<div id="testMe" contenteditable="true" class="form-control"></div>
<div id="myModal" class="modal fade">
<div class="modal-dialog">
<div class="modal-content">
<div class="modal-body">
<p> You are not allowed to use this character.</p>
<p> Press OK to dismiss.</p>
</div>
<div class="modal-footer">
<button id="closeAlert" type="button" class="btn btn-danger">OK</button>
</div>
</div>
</div>
</div>
$("#testMe").keypress(function(event) {
console.log("key pressed");
if (String.fromCharCode(event.which) == ".") {
event.preventDefault();
$('#myModal').modal('show');
}
});
$("#closeAlert").click(function() {
$('#myModal').modal('hide');
});
Click inside the contenteditable
Press "." character (no input appears and a "keypress" message is printed to the console).
Dismiss the dialog
Press "." character again (the input appears and no keypresssmessage appears in the console log).
It turns out that the problem was in setting back the focus of the element. Adding
$("#testMe").focus();
after hiding the modal fixes it.
I had originally used the bootbox library for showing modals. For unclear reasons, setting focus immediately after the dialog close callback doesn't work with it.

How to handle tap events without blocking UI visualization changes in a listview

Using a jQuery Mobile button like:
<ul data-role="listview">
<li><a data-role="button" href="#" id="test">Test</a></li>
</ul>
I am attaching a tap handler like this:
$('#test').on('tap', function(event) {
event.preventDefault();
window.console.log('do something useful here');
});
The problem is that either preventDefault is blocking the JQM css changes to buttons like ui-btn-down/active/up/etc. or just adding the tap handler at all is preventing them. So it doesn't quite feel right to the user cause there is no visual impact of clicking the button.
Is there anyway around this problem? Perhaps manually assigning the classes in each handler - though that seems heavy handed.
Instead of preventing default actions of a link, you can use the button element:
<div role="main" class="ui-content">
<button id="test">Test</button>
<br /><br />
<input type="text" value="" id="output" />
</div>
$('#test').on('tap', function(event) {
$("#output").val(new Date());
});
jQM styles the button the same way, so there is no real difference.
Working DEMO
Upon further testing, my premise for this question was wrong. The issue appears to be the duration of the tap itself. If you tap too quickly the classes don't get applied, but a few ms longer and they do. I am closing this question.

Categories

Resources