We are trying to scroll an element on our iOS web app while preventing the window itself from scrolling. We are capturing the touchmove event on the window, scrolling the element programmatically and (trying to) prevent the window itself from scroll by calling preventDefault on the event.
Unfortunately this doesn't work in Mobile Safari. The window continues to scroll underneath our element. The issue sounds exactly like the Webkit bug described in https://bugs.webkit.org/show_bug.cgi?id=163207, but that issue was supposedly fixed in iOS 10.3 whereas I am running 11.3.
Catching touchforcestart and calling preventDefault does seem to prevent scrolling of the window, but we are calling it in touchstart, which seems to be "too late" since the window still scrolls. Scrolling is only prevented next time touchstart is called.
Any ideas about what is going on? We are baffled since this is clearly a bug but it seems to have been fixed some time ago.
I recently ran into this same problem. You'll need to pass { passive: false } when registering the touchmove event listener. e.g.
document.addEventListener('touchmove', function(e) {
e.preventDefault();
}, { passive: false });
This is because document touch event listeners are now passive by default in Safari 11.1, which is bundled with iOS 11.3. This change is documented in the Safari 11.1 release notes:
Web APIs
[...]
Updated root document touch event listeners to use passive mode improving scrolling performance and reducing crashes.
You need to bind preventDefault to two events: touchmove and touchforcechange to make it work in ios 11, e.g.
document.addEventListener('touchmove', this.preventDefault, {passive: false});
document.addEventListener('touchforcechange', this.preventDefault, {passive: false});
And you should bind them before touchstart
If you bind them inside your touchstart or dragStart handler, they can only prevent scroll in the next dragging.
What worked for me was to pass the {passive:false} option to addEventListener (explanation), and you also need to make sure you execute e.preventDefault() on touchmove and touchstart:
window.addEventListener("touchstart", e=>e.preventDefault(), {passive:false});
window.addEventListener("touchmove", e=>e.preventDefault(), {passive:false});
Related
I am currently working on Wes Bos' JavaScript 30 project, and in this drumkit project, I was hoping to add to his finished code by allowing user to click on the button rather than only through 'keydown' event.
After adding to the playSound function to detect
event.path[1].dataset.key || event.path[0].dataset.key
so that the click event would be able to grab the button's attribute, which contains the keyCode, and use that to detect which audio to play. Then I wrote this:
window.addEventListener('click', playSound);
and it worked great on desktop, it also worked great on my android smart phone, but for some reason the button doesn't work on an iphone.
So after looking through some similar results on stackoverflow, here's what I've tried:
window.addEventListener('touchstart', playSound)
and
window.addEventListener('DOMContentLoaded', (event) => {
window.addEventListener('touchstart', playSound)
});
but neither of them seems to work on iphone. Is there something special about iphone that doesn't allow me to click a button using their touch screen? Android doesn't seems to have this issue at all.
it turns out all i needed to do is use document.addEventListener instead of window.addEventListener for iOS
I want to create a button-like component with ripple animation and it looks like this:
<div>Button</div>
<material-ripple></material-ripple>
In the past, this works fine because when I click on this custom element, I actually clicks on material-ripple and the click event bubbles to the host element.
As of angular_components 0.5.1, material-ripple shows a centered ripple on keypress. This is different from clicking because the event target is the host element itself and not the ripple component.
Is there a way that I can pass a keypress event down to the material-ripple, so that the ripple animation would be played? Or is there a way to play the animation programmatically?
After some research, I've come up with a solution using dart:html.
#ViewChild(MaterialRippleComponent, read: ElementRef)
ElementRef materialRipple;
#HostListener('keydown', const [r'$event'])
void passKeyDown(KeyboardEvent event) {
(materialRipple.nativeElement as HtmlElement).dispatchEvent(
new KeyEvent('keydown', keyCode: event.keyCode, canBubble: false)
.wrapped);
}
Although this does not work in Dartium due to some bugs around KeyEvent and KeyboardEvent, it works fine in Chrome.
On Safari 10, by defining a simple listener that prevents default a touchmove event within a scrollable element, the event is not default prevented as it does with Safari 9 and less (it also does in all major browsers).
This is reproducible here: http://codepen.io/anon/pen/PGRxOv
Steps to Reproduce:
Take an element with scrollable content (overflow: scroll).
Add an event listener on it for touchmouve event, and call event.preventDefault() in that event listener.
Expected Results:
The element should not be scrollable.
Actual Results:
The element is still scrollable on Safari 10.
Version:
iOS 10.0.2
Probably a webkit issue...I opened an issue on webkit bug tracker.
In the mean time, if anyone has a workaround (except prevent the touchstart), it would be great :)
I also tried to return false in the listener but it does not work either.
You need to pass the {passive:false} option to addEventListener (explanation), and you also need to make sure you execute e.preventDefault() on touchmove and touchstart:
window.addEventListener("touchstart", e=>e.preventDefault(), {passive:false});
window.addEventListener("touchmove", e=>e.preventDefault(), {passive:false});
Thanks for writing about this and raising an issue — it had me completely baffled!
Your codepen solution didn't seem to work for me, but I have since found another solution here: https://github.com/metafizzy/flickity/issues/457
This is their solution:
window.addEventListener( 'touchmove', function() {})
Feels very hacky but has worked for my situation.
I hope this helps anyone else frustrated by this.
I am creating an iPad app in which I have a textInput component that when it is in focus is suppose to call a callout with a spinner in it. The problem is that the softkeyboard is showing up every time I touch the textInput component. I have tried everything I could find which includes the following:
private function onActivating(event:SoftKeyboardEvent):void
{
event.preventDefault();
}
<s:TextInput softKeyboardActivating="onActivating(event)" />
and
<s:TextInput needsSoftKeyboard = "False"/>
Both of these examples are still having the softkeyboard show up.
Have you tried to simply disable the TextInput and change the styles so it doesn't look disabled? Touch events may not trigger though but short of styling a label [as suggested above] you'll have to do some trickery one way or another.
I want to silently scroll the window when the page is completely loaded, so I call silentScroll inside the initPage listener. However, it doesn't work, no scrolling.
$('#mainPage').live( 'pageinit', initPage);
function initPage() {
$.mobile.fixedToolbars.setTouchToggleEnabled(false);
$.mobile.silentScroll(800);
....
The only way I can get it to work is to call it via setTimeout, but why? The page should be ready when pageinit is executed, referring to the jqm docs on http://jquerymobile.com/demos/1.0/docs/api/events.html.
With this, automatic scroll works, but it's ugly:
setTimeout(function(){$.mobile.silentScroll(8000);}, 1000); // scroll after 1 sec
Executing $.mobile.silentScroll(8000); in Firebug / Chrome dev tools also works ok, just not in initPage. When I display an js alert in initPage, it's being shown. But the scrolling is just not being executed properly. Maybe a jqm bug?
Detailed answer to this question here:
https://github.com/jquery/jquery-mobile/issues/3461