iScroll 4 not working with form <select> element iPhone Safari and Android browser
Asked Answered
P

19

26

I'm using this HTML code:

<form action="#" method="post">
    <fieldset>
        <label class="desc" id="title10" for="Field10">
            How many children do you have?
        </label>        
        <select id="Field10" name="Field10" class="field select large" tabindex="5">
            <option value="0" selected="selected">0 </option>
            <option value="1">1 </option>
            <option value="2">2 </option>
            <option value="3">3 </option>
            <option value="4">4 </option>
            <option value="5">5 </option>
            <option value="6">6 </option>
            <option value="7">7 </option>
            <option value="8">8 </option>
            <option value="9">9 </option>
        </select>
        <input type="submit" value="Send message" />
    </fieldset>
</form>

<select> is not working on iPhone and Android. When I tap on the selectbox nothing happens.

I'm using iScroll 4 which is creating the problem.

<script type="application/javascript" src="iscroll-lite.js"></script>
<script type="text/javascript">
    var myScroll;
    function loaded() {
        myScroll = new iScroll('wrapper');
    }
    document.addEventListener('touchmove', function (e) { e.preventDefault(); }, false);
    document.addEventListener('DOMContentLoaded', loaded, false);
</script>

I think this is a solution but I don't know how to implement it.

Pectinate answered 21/4, 2011 at 14:20 Comment(7)
nothing happens when I tap on <select> dropdownPectinate
I'm also using iscroll4 on the pagePectinate
Do you have a demo that reproduces the problem for us to see?Suk
I just searched on net that iscroll has problem with form elements. searching for solution.Pectinate
@JitendraVyas I ran into this problem in an JQM 1.0 project, what I found was that you need to do a check to see what kind of element node the user has pressed. If it is a form element, kill your iScroll instance. Else (not a form element) check to see if there's already an iScroll instance for that particular page, if so, go about things as usual (normal behavior), but if not, initialize a new iScroll instance (so you can scroll). Doing this should allow you to fix all the form elements on your page, without having attach an eventlistener to or loop through each form element on a given page.Carnivore
This has been fixed now in iScroll 5 and works great. Earlier putting the hack on input (or select) field you won't be able to scroll the screen by touching input field. This has been too taken care in iScroll 5.Bikini
@Mahendra I'm using the Iscroll5 and I have that problem too.Astraphobia
C
46

The problem is that iScroll cancels the default behavior of your select tag (Not a very good implementation if you ask me).

This occurs in the _start() function on line 195:

e.preventDefault();

If you comment that out you'll notice the select tag works again.

But commenting it out means you've hacked the library which might break other desirable iScroll functionality. So here's a better workaround:

var selectField = document.getElementById('Field10');
selectField.addEventListener('touchstart' /*'mousedown'*/, function(e) {
    e.stopPropagation();
}, false);

That code will allow the default behavior to occur, without propagating the event to iScroll where it screws everything up.

Since your JS is not inside any jQuery-like onReady() event, you'll have to make sure to you put this code AFTER the HTML where your select elements are defined.

Note that for mobile devices the event is touchstart, but for your PC browser it will be mousedown

Clothier answered 24/4, 2011 at 8:1 Comment(11)
By the way, have this up and running here if you want to test it or see the full source: edrooth.com/testClothier
@Clothier - Thanks for answer. Will it also solve the problem in Android browser? and Instead of 'Field10' can't we use 'select' because I want to fix all select elements on page.Pectinate
It should work in Android too, but I can't say for sure b/c I don't have an android phone. I tested it in the iPhone and it works. And sure, you can do the same thing for all select tags, just call getElementsbyTagName('select') and loop through them all.Clothier
By the way, this should work in Android b/c all my code does is undo what iScroll does to the select element. There's no additional code specific to either environment.Clothier
I'm accepting your answer but Select dropdown flashing on focus so not real benefit.Pectinate
ok thanks, but I really don't think the flashing is related. The flashing is likely a CSS problem.Clothier
But I just checked and I think the problem is still there jsbin.com/unese4/8 I used iscroll origional demo page to make this jsbin page. Actually the problem is when select dropdown comes under the scroll area it's doesn't workPectinate
it's not working. Now the dropdown opens but when I go back to page i get white screenPectinate
iScroll took care of it github.com/cubiq/iscroll/blob/master/examples/form-fields/…Media
thanks umair, best comment so far, they really fixed all insert-problems.Nit
With the latest version of iScroll4 (as of today 4.2.5) it didn't work to edit any input fields on a jQuery Mobile 1.4.2 app - with pull to refresh functionality (as per the Qubic.org example). The solution above solved it for me, I adapted it to a jQuery version: $('input, select, textarea').on('touchstart mousedown', function(){ event.stopPropagation(); });Stylolite
F
10

I had the same issue on the iScroll 4.1.9 on android, I just replaced the line 95 (on my version) :

onBeforeScrollStart: function (e) { e.preventDefault(); },

by :

onBeforeScrollStart: function (e) {var nodeType = e.explicitOriginalTarget ? e.explicitOriginalTarget.nodeName.toLowerCase():(e.target ? e.target.nodeName.toLowerCase():''); if(nodeType !='select' && nodeType !='option' && nodeType !='input' && nodeType!='textarea') e.preventDefault(); },           

that enable focus on input, select and textarea tags

Forecastle answered 7/10, 2011 at 12:35 Comment(2)
would this have a problem when you upgrade iscroll? your modifying the library, isnt that dangerous?Edwardoedwards
But this causing iScroll. It doesn't scroll when tap and pull on any form elementsStulin
A
6

Finally fixed this for Android. Ended up modifying a couple of lines in iscroll.js

Here's how we initialize iScroll.

// code from https://github.com/cubiq/iscroll/blob/master/examples/form-fields/index.html
// don't preventDefault for form controls
_menuScroll = new iScroll('menu_wrapper',{
    useTransform: false,
    onBeforeScrollStart: function (e) {
        var target = e.target;
        while (target.nodeType != 1) target = target.parentNode;

        if (target.tagName != 'SELECT' && target.tagName != 'INPUT' && target.tagName != 'TEXTAREA')
        e.preventDefault();
    }
});

The onBeforeScrollStart is what allows the controls' default behaviors to take place. Android browser seems to have problem with useTransform, so turn to false.

Finally, some additional iscroll code needed to be excluded when useTransform is false:

// iscroll.js v4.1.9
// line 216:
if (that.options.useTransform) bar.style.cssText += ';pointer-events:none;-' + vendor + '-transition-property:-' + vendor + '-transform;-' + vendor + '-transition-timing-function:cubic-bezier(0.33,0.66,0.66,1);-' + vendor + '-transition-duration:0;-' + vendor + '-transform:' + trnOpen + '0,0' + trnClose;

// line 295:
if (that.options.useTransform) that[dir + 'ScrollbarIndicator'].style[vendor + 'Transform'] = trnOpen + (dir == 'h' ? pos + 'px,0' : '0,' + pos + 'px') + trnClose;

Tried several other methods before realizing that it had to do with the css that iscroll adds.

Ankus answered 19/1, 2012 at 23:43 Comment(2)
you need to add OPTION to the set of tags tested in the beforescrollstart handlerAnima
But this causing iScroll. It doesn't scroll when tap and pull on any form elementsStulin
P
4

I Know am late,but it might be helpful for some one,

write the following code in pageshow event,but be sure that div ids not same.

it is because, iscroller prevents the default behaviors of elements

 $('#yourpage').bind('pageshow',function (event, ui) {

       var myScroll;

         if (this.id in myScroll) {
         myScroll[this.id].refresh();

         }else{ 

          myScroll[this.id] = new iScroll('wrapper', { //wrapper is div id
                   checkDOMChanges: true,
                   onBeforeScrollStart: function (e) {
                         var target = e.target;
                         while (target.nodeType != 1) 
                         target =target.parentNode;

                   if (target.tagName != 'SELECT' && target.tagName != 'INPUT' && target.tagName != 'TEXTAREA'){  e.preventDefault();  }
                                 }
                               });
                            }
     document.addEventListener('touchmove', function (e) { e.preventDefault(); }, false);

     });
Perry answered 10/12, 2012 at 10:55 Comment(1)
I just added the onBeforeScrollStart code you have and it works great. Selected answer had unwanted side effects. Thanks.Incommensurable
L
3

Here is the solution

/* on page add this after all scripts */
    <script type="text/javascript">
            var myScroll;
            function loaded() {
                myScroll = new iScroll('wrapper');
            }
            document.addEventListener('DOMContentLoaded', function(){ setTimeout(loaded,500);}, false);
    </script>

/* attach a script for fix */
        $(document).ready(function(){
            var my_select = document.getElementsByTagName('select');
            for (var i=0; i<my_select.length; i++) {
                my_select[i].addEventListener('touchstart' /*'mousedown'*/, function(e) {
                    myScroll.destroy();
                    setTimeout(function(){myScroll = new iScroll('wrapper');},500);
                }, false);
            }

    /*if you have input problems */

            var input = document.getElementById('input');

            if (input) {
                input.addEventListener('touchstart' /*'mousedown'*/, function(e) {
                    e.stopPropagation();
                }, false);
            }    
        });
Liquefy answered 8/6, 2011 at 8:10 Comment(2)
I have used comonitos 's solution on Android 2.3.4 and it did not work, I am using iScroll 4.2 and jQM 1.1.0, I have also tried this solution inside the plugin jquery.mobile.iscrollview.js but it did not work either. comonitos, which version of jQM and iScroll are you using? Does anybody knows a workaround for Android?Convalescence
it was jquery.mobile-1.0a4 and iScroll v4.0 Beta 4. a can send you my libsLiquefy
R
2

another code example for solution. and thanks for previous comments! Using Jquery!

After:

$(document).ready(function() {            
    document.addEventListener('touchmove', function (e) { e.preventDefault(); }, false);

    document.addEventListener('DOMContentLoaded', setTimeout(function () { loaded(); }, 200), false);
});

in loaded function

function loaded() {
    var allSelects = $('select');
    allSelects.each(function(index, item) {
                        item.addEventListener('touchstart' /*'mousedown'*/, function(e) { e.stopPropagation(); }, false);
                    });
}
Rafat answered 14/11, 2011 at 9:43 Comment(0)
A
2

Replacing line, onBeforeScrollStart: function (e) { e.preventDefault(); },

By

onBeforeScrollStart: function (e) {
    var nodeType = e.explicitOriginalTarget ? e.explicitOriginalTarget.nodeName.toLowerCase():(e.target ? e.target.nodeName.toLowerCase():'');

    if(nodeType !='select' && nodeType !='option' && nodeType !='input' && nodeType!='textarea') {
         e.preventDefault();
    }
},

In iScroll.js Works

Aperient answered 23/4, 2012 at 10:56 Comment(0)
A
2

Start with this code. This solution worked for me:

<script type="text/javascript">

var myScroll;
function iScrollLoad() {
    myScroll = new iScroll('wrapper');
    enableFormsInIscroll();
}

function enableFormsInIscroll(){
  [].slice.call(document.querySelectorAll('input, select, button, textarea')).forEach(function(el){
    el.addEventListener(('ontouchstart' in window)?'touchstart':'mousedown', function(e){
      e.stopPropagation();
    })
  })
}

document.addEventListener('touchmove', function (e) { e.preventDefault(); }, false);
document.addEventListener('DOMContentLoaded', function () { setTimeout(iScrollLoad, 200); }, false);

</script>
Antirachitic answered 4/12, 2012 at 19:42 Comment(0)
Z
1

I'm late but I leave you my solution.

If your are using jQuery you can try that.

$('input, textarea, button, a, select').off('touchstart mousedown').on('touchstart mousedown', function(e) {
    e.stopPropagation();
});
Zelmazelten answered 22/5, 2013 at 12:54 Comment(0)
C
1
  // Setup myScroll
  myScroll = new IScroll('#wrapper', {
    scrollX: horizontalSwipe,
    scrollY: !horizontalSwipe,
    momentum: false,
    snap: document.querySelectorAll('#scroller .slide'),
    snapSpeed: 400,
    bounceEasing: 'back',
    keyBindings: true,
    click: true
  });

For me, I just need to add click: true on the last line... Spent the whole day debugging and implementing all the suggested solutions to no avail...

Charismatic answered 30/5, 2013 at 9:50 Comment(1)
This question was about iScroll 4 - your solution is made for the version 5. Anyways good to know.Actinal
I
1

he anyone.

i know's about all your answer's but i have new way to offer. without java-script or drop iscroll functions.

the big problems with all this solution is when you scroll on input's element you have no scroll on the page. when you make just one or two input's isn't really matter but when the page is a form you have big problem to scroll the page.

the solution i offering is to wrap the input in label tag or make the label tag with for pointer to the input. then make with absolute positioning and z-index the label above the input. when you touch on the label you focus the input.

and example please

HTML

<fieldset>
<label>
    <input type="text" />
</label>
</fieldset>

CSS

fieldset {position:relative;z-index:20;}
label {position:relative;z-index:initial;}
input {position:relative;z-index:-1;}

you can also in this way put the label side of the input and with position absolute of the input put that into the label area

is working in 100%, check it

Inexplicable answered 30/6, 2013 at 12:47 Comment(0)
P
0

There is a bug with Android when -webkit-transform:translate3d is applied to a container that has a select box or password box[1]. The boxed area to activate those elements move, and are not where you think they'd be. Additionally, password boxes paint in a different location, so it appears that you have two input elements instead of one.

I work at AppMobi and we have developed a toolkit library that has fixes for these. We've implemented custom select box widgets and a replacement for the password input field. Check it out below.

https://github.com/imaffett/AppMobi.toolkit

[1] I think the author of the comment is talking about this bug https://bugs.webkit.org/show_bug.cgi?id=50552

Prosopopoeia answered 9/5, 2011 at 17:11 Comment(0)
W
0

Here's a really easy fix that worked for me. I noticed in the Android browsers that on initial page load I could not click on a select box but I was able to click on a text input field that I was using for Search. Then I noticed that after I clicked on the text input field, it would recognize me clicking a select box. So all I did was add this to the javascript function I was using to load the Search page...

$('#search').focus();

So when the search page gets loaded, it automatically focuses on the text input field but does not pop up the keyboard, which is exactly what I wanted. Sorry my example is not publicly accessible, but hopefully this can still help somebody.

Weave answered 3/1, 2012 at 16:33 Comment(0)
C
0

I'm a bit late to the game, but if anyone is still interested, I took @bastien's approach and tweaked it a bit to get it to work on Android. I'm using JQM with my implementation.

Basically what I did was:

function scrollMe(element) {

var contentID = $wrapper.get(0).id;
var scroller = elm.find('[data-iscroll="scroller"]').get(0);
if (scroller) {
    var iscroll = new iScroll(contentID, {
        hScroll        : false,
        vScroll        : true,
        hScrollbar     : false,
        vScrollbar     : true,
        fixedScrollbar : true,
        fadeScrollbar  : false,
        hideScrollbar  : false,
        bounce         : true,
        momentum       : true,
        lockDirection  : true,
        useTransition  : true, 
        //the preceding options and their values do not have any to do with the fix
        //THE FIX:
        onBeforeScrollStart: function(e) {
            var nodeType = e.explicitOriginalTarget ? e.explicitOriginalTarget.nodeName.toLowerCase() : (e.target ? e.target.nodeName.toLowerCase():''); //get element node type
            if(nodeType !='select' && nodeType !='option' && nodeType !='input' && nodeType!='textarea') e.preventDefault(); //be have normally if clicked element is not a select, option, input, or textarea.
            else if (iscroll != null) {   //makes sure there is an instance to destory
                     iscroll.destroy(); 
                     iscroll = null;
            //when the user clicks on a form element, my previously instanced iscroll element is destroyed
            }
        },
        onScrollStart: function(e) { 
            if (iscroll == null) {  //check to see if iscroll instance was previously destoryed 
                var elm = $.mobile.activePage; //gets current active page
                var scrollIt = setTimeout( function(){ scrollMe(elm) }, 0 ); 
            } //recursively call function that re-instances iscroll element, as long as the user doesn't click on a form element
        } 
    });
    elm.data("iscroll-plugin", iscroll);
}

}

Basically all you need to do is destroy your iScroll instance when a form element is selected by the user, but before they actually start scrolling (onBeforeScrollStart) and if the user clicks on anything else within the element with the custom attribute data-iscroll="scroller", they can scroll using iScroll as usual.

<div data-role="page" id="pageNameHere" data-iscroll="enable">
Carnivore answered 24/8, 2012 at 3:41 Comment(0)
U
0

try this solution if (e.target.nodeName.toLowerCase() == "select" || e.target.tagName.toLowerCase() == 'input' || e.target.tagName.toLowerCase() == 'textarea') {
return; }

Uncommon answered 22/11, 2012 at 9:28 Comment(0)
T
0

What about, that works for me!:

$('input, select').on('touchstart', function(e) {
    e.stopPropagation();
});
Terylene answered 23/7, 2013 at 11:4 Comment(0)
E
0

Even if you've excluded form elements in onBeforeScrollStart(), there is another bug in android 2.2/2.3 browser/webview:

https://www.html5dev-software.intel.com/viewtopic.php?f=26&t=1278 https://github.com/01org/appframework/issues/104

You can't input chinese characters in input elements in the div with "-webkit-transform" css style. The iscroll 4 applied the "-webkit-transform" with the scroller div.

The solution is to keep form fields in a absolute div out of the scroller.

Epiphenomenon answered 20/9, 2013 at 14:27 Comment(0)
J
0

Android browser bug is result of very old version of WebKit inside Android, even inside Android 4.3. The root cause of bug - wrong processing of the click event that iScroll sends back to the browser (removing preventDefault just stops sending this click event) The Android Chrome browser is free from this bug because it has upgraded WebKit library inside.

Waiting for Android WebKit upgrade from Google.

Jaye answered 29/10, 2013 at 13:17 Comment(0)
G
0

Check this. This fixed my issue

https://github.com/cubiq/iscroll/issues/576

In option I have selected

click:false, preventDefaultException:{tagName:/.*/}
Gurglet answered 7/8, 2018 at 16:22 Comment(0)

© 2022 - 2024 — McMap. All rights reserved.