I'm writing an app in phonegap with a specific 'zoom-in' effect when clicking on an input element (everything but the input hides and custom typeahead suggestions are shown). The view is written using backbone.js and i'm entering the 'zoomed-in' mode on focus:
events: {
'focus .search': 'startSearch',
}
In my startSearch method i'm doing all the logic to immitate the zoom-in effect.
_moveCursorToEnd: function(element) {
var val_len = element.value.length;
element.scrollLeft = val_len * 9;
setTimeout(function() {
element.selectionStart = val_len;
}, 1);
},
startSearch: function() {
window.navbar.hide();
this.$input.addClass('search-input-small');
this.$cancel.show();
var el = this.$input[0];
this._moveCursorToEnd(el);
},
The search-input-small makes the input smaller.
The setTimeout in _moveCursorToEnd is required because the effect doesn't work otherwise. The issue is that despite setTimeout having 1msec, it looks like a second cause inconvenient cursor move.
Is there any way to move the cursor to the end that would work on Safari Mobile 6 (iOS 6+) without the ugly delay?
I've ended up changing the event from focus to click and using similar code as mentioned above so that it works. Seems like the selection from a click that focused the text edit is applied after focus handler and before click handler.
Related
I tried to disable auto focus of input search inside select2 especially on mobile to disable keyboard popup. However, as documented here:
select2 will not be triggering the native events. select2 will also
not be triggering non-native versions of the events, which is less of
an issue as we still have the option to add the native events without
breaking compatibility.
So the only way I could do is to try to get every input box inside select2 that was currently on focused and set lose focus, but has no luck.
$("select").select2().on("select2-open",":input",function(){
setTimeout(function(){
$(":focus").blur();
}, 50);
});
Is there any possibility that I could achieve that result above? Thanks.
Finally, I managed to find solution which works just fine for me as below:
/* Hide keyboard on select2 open event */
function hideSelect2Keyboard(e){
$('.select2-search input, :focus,input').prop('focus',false).blur();
}
$("select").select2().on("select2-open", hideSelect2Keyboard);
$("select").select2().on("select2-close",function(){
setTimeout(hideSelect2Keyboard, 50);
});
Tested on Tablet, and iOS device. In function hideSelect2Keyboard(), I searched for every current focus element, include input field which could be used to initialized select2, setting .prop('focus',false) which will remove focus and consequently disable keyboard popup on select2-open and select2-close event, by chaining .blur() is to remove focus border from element. Then I attached this function to select event open and close and it works just fine.
I hope this will help other who searching for this as me too. Thanks.
I think I've found a solution for select v3 - tested in v3.5.4.
We can use the option shouldFocusInput, which must be a function that should return true or false.
So initialize the plugin with the following code:
$(document).ready(function() {
$('select').select2({
shouldFocusInput: function() {
return false;
}
});
});
Codepen demo: https://codepen.io/andreivictor/pen/JmNzvb
If you want to disable the auto-focus only on mobile devices, my approach is to use Modernizr library, which can test for the existence of Touch Events in the browser.
So the complete code should be:
$(document).ready(function() {
$('select').select2({
shouldFocusInput: function() {
if (Modernizr.touch) {
return false;
}
return true;
}
});
});
I am not sure why, but the above solutions didn't work for me. But this one worked-
$('select').on('select2:open', function (event) {
$('.select2-search input').prop('focus',false);
});
in my Cordova App I have a problem on iOS devices and I have no idea how to solve.
I have a custom auto-suggest which shows up below an input field while typing. All is contained in a dialog box with "position: fixed;".
Autocomplete is an unordered list. Click on < li > Element should place the selected text into the input.
The problem is, when user clicks on the li, the input loses focus, the keyboard disappears and the whole fixed dialog box "jumps" down and the click event is not recognized.
It is recognized when the keyboard already IS closed.
I tried several workarounds, like giving focus back to input field immediately after blur. But it does not help. Keyboard closes and opens instead of just keeping opened.
Any Ideas how to solve?
Here is a video showing the behaviour. It is recorded on the iOS Simulator but same behaviour on real iPhone 6s.
I have found a solution now. As I said the click event is not triggered when the keyboard hides, but a touchstart event is triggered.
So I did a workaround, looking for touchstart event followed by a blur event. If the touchstart-target does not receive a click event within a given time, I will trigger one. This works on my test iPhone 6s.
Here is the code:
var iosTapTarget=null;
if (device.platform === 'iOS') {
js.eventListener(document.body).add('iosTap', 'touchstart', function (e) {
iosTapTarget = e.target;
js.eventListener(iosTapTarget).add('iosTapClick', 'click', function(e) {
// when the target receives a click, do not trigger another click
if (iosTapTarget) js.eventListener(iosTapTarget).remove('iosTapClick', 'click');
iosTapTarget = null;
});
// after short time unset the target
window.setTimeout(function () {
if (iosTapTarget) js.eventListener(iosTapTarget).remove('iosTapClick', 'click');
iosTapTarget = null;
}, 600)
});
// on each input fields listen for blur event and trigger click event on element received touchstart before
var blurableElements = document.querySelectorAll('input[type=text],input[type=email],input[type=password],textarea');
for (var j = 0; j < blurableElements.length; ++j) {
js.eventListener(blurableElements[j]).remove('iosBlur', 'blur');
js.eventListener(blurableElements[j]).add('iosBlur', 'blur', function () {
window.setTimeout(function() {
if (iosTapTarget) {
js.eventListener(iosTapTarget).remove('iosTapClick', 'click');
js.triggerEvent(iosTapTarget, 'click');
}
}, 50);
});
}
}
PS: Event handling comes from my own JS "framework" js.js available here: https://github.com/JanST123/js.js
But you can use vanilla JS event handling or jQuery event handling too, of course.
I have a web app. I'm trying to disable/prevent the scrolling that occurs when you focus on different form inputs (i.e. the scrolling that occurs as you advance through input elements in a form).
I've already disabled scrolling with this:
<script type="text/javascript">
$(document).ready(function() {
document.ontouchmove = function(e){
e.preventDefault();
}
});
</script>
To add a little more info - I have a few "slides" that my page consists of. Each are 768x1024 and they are "stacked" on the page (i.e. the page is 768x3072 [1024*3=3072]) and when you click a link I'm using scrollTo jquery plugin to scroll to the next "slide" and .focus() on an input element.
Does anyone know how to do this?
I've found that in UIWebView, document.body is also sometimes moved. So I use:
input.onfocus = function () {
window.scrollTo(0, 0);
document.body.scrollTop = 0;
}
Ooops, the window.scrollTo suggested is kinda lousy and make things unpredictable.
Try this better solution:
jQuery('body').bind('focusin focus', function(e){
e.preventDefault();
})
Or, just hook your input:
jQuery('input.your-input-class').bind('focusin focus', function(e){
e.preventDefault();
})
Why? Browsers may scroll the focused form element into view by default on 'focusin' event fired (Firefox has a bug, so hook on focus instead). So, just tell them don't do that explicitly.
BTW, if the focus event is triggered by element.focus() in your code, then even the upon solution would not be functional.
So, a solution to that would be replace you focus trigger to select, i.e.
element.select()
other than element.focus()
If you don't like the element.select() approach since it will select the text inside the input element, then try to create a Range object of the input element text and collapse it if you will, sorry for no time to try that at this moment.
To prevent the browser from scrolling to the element you move focus to I use jQuerys one event listener. Right before I move the focus to the element we add the listener to the scroll event and counter scroll. The event listener is than removed by jQuery.
var oldScroll = $(window).scrollTop();
$( window ).one('scroll', function() {
$(window).scrollTop( oldScroll ); //disable scroll just once
});
$('.js-your-element').focus();
This way seems simple, effective to me and works great in all tests I have done.
Hope it helps someone.
If you do not want the input to be editable the answer from kpozin works fine. But as soon as you remove the readonly attribute onfocus or onclick the input field scrolls in focus again.
What really helps and does not impact focus or ability to enter text is adding onFocus="window.scrollTo(0, 0);" to the input elements.
Of course you have to guarantee that the relevant input is not covered by the onscreen keyboard!
See also this post: Preventing an <input> element from scrolling the screen on iPhone?
Update on this - I've seen the window.scroll(0,0) solution in a couple of different places but it seemed to just make it worse. I have multiple inline text inputs on my page so when moving focus between them the automatic up and down scrolling in Safari made the page almost unusable, especially in landscape orientation.
After fighting iOS 8 for a week on this I found this stops the scrolling. This works when changing focus from one element to another as you need to attach the onblur event to something:
var moveFocus = function (blurId, focusId) {
var blurInput = document.getElementById(blurId);
var focusInput = document.getElementById(focusId);
if (blurInput && focusInput) {
blurInput.onblur = function () {
if (focusInput.setSelectionRange && focusInput.setSelectionRange()) {
var len = focusInput.value.length;
focusInput.setSelectionRange(len, len);
}
focusInput.focus();
};
focusInput.focus();
};
};
Try this answer by BLSully. Give all your input elements a readonly="readonly" attribute initially. This will prevent Mobile Safari from scrolling to it. Remove the attribute on focus and add it again on blur for each element.
For whatever reason, it appears you can mitigate this by applying a keyframe animation to an autoFocused input container.
function App() {
const [isSearching, setIsSearching] = useState(false);
return (
<FixedContainer>
{isSearching && (
<Box>
<Input autoFocus type="text" placeholder="click me" onBlur={() => setIsSearching(false)} />
</Box>
)}
</FixedContainer>
)
}
const fadeInKeyframes = keyframes`
0% {
opacity: 0;
}
100% {
opacity: 1;
}
`;
const Box = styled.div`
animation-name: ${fadeInKeyframes};
animation-duration: 0.1s;
animation-timing-function: ease;
animation-delay: 0s;
animation-iteration-count: 1;
animation-direction: normal;
animation-fill-mode: forwards;
animation-play-state: running;
`;
https://stackblitz.com/edit/react-ios-input-scroll
Working example: https://react-ios-input-scroll.stackblitz.io
This worked for me (using jQuery). It allows the scroll and then returns you to the proper position when you leave the input.
var saveScrollLeft;
$("input, textarea")
.focus(function () {
clearTimeout(blurTimeoutId);
saveScrollLeft = $("body").scrollLeft();
})
.blur(function () {
// The user might be moving from one input to another, so we don't want to quickly scroll on blur. Wait a second and see if they are off all inputs.
blurTimeoutId = setTimeout(function () {
$(window).scrollLeft(saveScrollLeft);
}, 1000);
});
None of the provided solutions worked for me.
Since the form that is grabbing the focus (and scrolling page initial display to said form) is below the fold, I simply added a fade-in to the form.
So I add a class name called fade-in, which corresponding css to display:none
using jQuery I then simply do jQuery(".fade-in").fadeIn(); after document ready, and the issue is gone.
This is obviously not limited to using jQuery. Vanilla js can be used for the fade.
In case you are developing a mobile webapp with cordova, there is a plugin for that:
The plugin that solved the problem for me was the Telerik Keyboard Plugin. It is using the basic UIWebView. Install the plugin
cordova plugin add ionic-plugin-keyboard
And call this command after your app loaded:
cordova.plugins.Keyboard.disableScroll(true);
In case you are using the WKWebView, you can use e.g. this plugin
To "focus" without any scroll, you may use select. select by default will select all of the text inside an input. To mimic focus behavior and have the caret at the end of the input you can use:
var myInput = document.getElementById('my-input');
var length = myInput.value.length; // Or determine the value of length any other way
myInput.select();
myInput.setSelectionRange(length, length);
If you use element.focus(), change it to element.focus({ preventScroll: true }).
But I'm not sure if it is working on Safari: https://developer.mozilla.org/en-US/docs/Web/API/HTMLOrForeignElement/focus
Right now I'm using a bit of jQuery to hide the iPad keyboard when an input loses focus.
jQuery(function($) {
$(document).on('touchend', function(e) {
document.activeElement.blur();
});
});
However during a process like the checkout when a user clicks from input to input the keyboard disappears and the reappears every time the input is changed. Is there any way to change the above jquery code to where it only blurs the active element if the place on the document that is touched does NOT have an input type of text?
Well, I haven't tried this with iPad before, so I'm not sure that it will work, but you can check the type of document.activeElement to determine if it is a text or textarea field. If it isn't, then perform your blur(). The code would be like this:
jQuery(function($) {
$(document).on('touchend', function(e) {
setTimeout(function() {
var currentElement = document.activeElement;
if ($(currentElement).not("textarea, :text").length > 0) {
currentElement.blur();
}
}, 100);
});
});
The setTimeout is needed to make sure that the focus has transferred to the next element, before checking what the current element is (doing it immediately, will return the <body> as the activeElement).
This general approach (i.e., identifying what type the current activeElement is) works in a desktop browser environment, and it SHOULD work on an iPad, but, like I said earlier, I've not had a chance to test it there, so this is more of a "possible solution" than an actual "answer", until you give it a try and se if it works for you. :D
I am using jQuery 1.3.2.
There is an input field in a form.
Clicking on the input field opens a div as a dropdown. The div contains a list of items. As the list size is large there is a vertical scrollbar in the div.
To close the dropdown when clicked outside, there is a blur event on the input field.
Now the problem is:
In chrome(2.0.172) when we click on the scrollbar, the input field will loose focus.
And now if you click outside, then the dropdown won't close(as the input has already lost focus when you clicked on the srollbar)
In Firefox(3.5), IE(8), opera(9.64), safari() when we click on the scrollbar the input field will not loose focus. Hence when you click outside (after clicking on the srollbar) the dropdown will close. This is the expected behaviour.
So In chrome once the scrollbar is clicked, and then if I click outside the dropdown won't close.
How can i fix this issue with chrome.
Well, I had the same problem in my dropdown control. I've asked Chrome developers concerning this issue, they said it's a bug that is not going to be fixed in the nearest future because of "it has not been reported by many people and the fix is not trivial". So, let's face the truth: this bug will stay for another year at least.
Though, for this particular case (dropdown) there is a workaround. The trick is: when one click on a scrollbar the "mouse down" event comes to the owner element of that scrollbar. We can use this fact to set a flag and check it in "onblur" handler. Here the explanation:
<input id="search_ctrl">
<div id="dropdown_wrap" style="overflow:auto;max-height:30px">
<div id="dropdown_rows">
<span>row 1</span>
<span>row 2</span>
<span>row 2</span>
</div>
</div>
"dropdown_wrap" div will get a vertical scrollbar since its content doesn't fit fixed height. Once we get the click we are pretty sure that scrollbar was clicked and focus is going to be taken off. Now some code how to handle this:
search_ctrl.onfocus = function() {
search_has_focus = true
}
search_ctrl.onblur = function() {
search_has_focus = false
if (!keep_focus) {
// hide dropdown
} else {
keep_focus = false;
search_ctrl.focus();
}
}
dropdow_wrap.onclick = function() {
if (isChrome()) {
keep_focus = search_has_focus;
}
}
That's it. We don't need any hacks for FF so there is a check for browser. In Chrome we detect click on scrollbar, allow bluring focus without closing the list and then immediately restore focus back to input control. Of course, if we have some logic for "search_ctrl.onfocus" it should be modified as well. Note that we need to check if search_ctrl had focus to prevent troubles with double clicks.
You may guess that better idea could be canceling onblur event but this won't work in Chrome. Not sure if this is bug or feature.
P.S. "dropdown_wrap" should not have any paddings or borders, otherwise user could click in this areas and we'll treat this as a scrollbar click.
I couldn't get these answers to work, maybe because they are from 2009. I just dealt with this, I think ihsoft is on the right track but a bit heavy handed.
With two functions
onMouseDown() {
lastClickWasDropdown=true;
}
onBlur() {
if (lastClickWasDropdown) {
lastClickWasDropdown = false;
box.focus();
} else {
box.close();
}
}
The trick is in how you bind the elements. The onMouseDown event should be on the "container" div which contains everything that will be clicked (ie, the text box, the dropdown arrow, and the dropdown box and its scroll bar). The Blur event (or in jQuery the focusout event) should be bound directly to the textbox.
Tested and works!
I was facing the same situation/problem and I tested the solution from "ihsoft" but it has some issues. So I worked on an alternative for that and made just one similar to "ihsoft" but one that works. here is my solution:
var hide_dropdownlist=true;
search_ctrl.onblur = function() {
search_has_focus = false
if (hide_dropdownlist) {
// hide dropdown
} else {
hide_dropdownlist = true;
search_ctrl.focus();
}
}
dropdow_wrap.onmouseover = function() {
hide_dropdownlist=false;
}
dropdow_wrap.onmouseoout = function() {
hide_dropdownlist=true;
}
I hope this will help someone.
Earlier also I faced such situation and this is what I have been doing.
$('html').click(function() {
hasFocus = 0;
hideResults();
});
and on the input field i will do this
$('input').click()
{
event.stopPropagation();
}
So this will close the drop down if clicked anywhere outside the div (even the scrollbar).
But I thought if someone could provide a more logical solution.
Could you maybe set the blur event to fire on the drop down div as well? This way, when either the input or the drop down loses focus, it will dissapear...
I'm curious...
You're using the last version of every browser, why don't you try it in chrome 4.0.202?
instead of detecting the blur, detect the document.body or window click and grab the mouse point. determine if this mouse point is outside of the menu box. presto, you've detected when they clicked outside the box!
I solved this by doing the following:
#my_container is the container which has the "overflow: auto" CSS rule
$('#my_container')
.mouseenter(function(){
// alert('ctr in!');
mouse_in_container = true;
})
.mouseleave(function(){
// alert('ctr out!');
mouse_in_container = false;
});
And then:
$('input').blur(function(){
if(mouse_in_container)
return;
... Normal code for blur event ...
});
When I select an element in the drop down, I rewrite the code as:
(>> ADDED THIS) mouse_in_container=false;
$('input').attr('active', false); // to blur input
$('#my_container').hide();