iScroll 4 not working with form dropdown – Jitendra Vyas Apr 21 '11 at 14:28

  • I'm also using iscroll4 on the page – Jitendra Vyas Apr 21 '11 at 14:37
  • Do you have a demo that reproduces the problem for us to see? – Matt Ball Apr 21 '11 at 14:39
  • I just searched on net that iscroll has problem with form elements. searching for solution. – Jitendra Vyas Apr 21 '11 at 14:42
  • 2
    @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. – Krazer Aug 24 '12 at 06:59
  • 1
    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. – Mahendra Liya Jan 25 '14 at 12:42
  • @Mahendra I'm using the Iscroll5 and I have that problem too. – msm.oliveira Jun 15 '15 at 08:43
  • 19 Answers19

    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

    Teun Zengerink
    • 4,277
    • 5
    • 30
    • 32
    sym3tri
    • 3,747
    • 1
    • 29
    • 25
    • By the way, have this up and running here if you want to test it or see the full source: http://edrooth.com/test/ – sym3tri Apr 24 '11 at 08:03
    • @sym3tri - 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. – Jitendra Vyas Apr 24 '11 at 08:30
    • 1
      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. – sym3tri Apr 24 '11 at 08:59
    • 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. – sym3tri Apr 24 '11 at 09:12
    • I'm accepting your answer but Select dropdown flashing on focus so not real benefit. – Jitendra Vyas Apr 24 '11 at 13:21
    • ok thanks, but I really don't think the flashing is related. The flashing is likely a CSS problem. – sym3tri Apr 24 '11 at 13:53
    • But I just checked and I think the problem is still there http://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 work – Jitendra Vyas Apr 24 '11 at 14:58
    • it's not working. Now the dropdown opens but when I go back to page i get white screen – Jitendra Vyas Jul 01 '11 at 08:05
    • 13
      iScroll took care of it https://github.com/cubiq/iscroll/blob/master/examples/form-fields/index.html – Umair A. Jul 31 '11 at 09:11
    • thanks umair, best comment so far, they really fixed all insert-problems. – dotchuZ Oct 12 '11 at 08:26
    • 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(); }); – jBoive Apr 29 '14 at 09:40
    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

    bastien
    • 131
    • 1
    • 5
    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.

    deCastongrene
    • 332
    • 3
    • 3
    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);
    
         });
    
    Mallikarjun
    • 191
    • 1
    • 5
    • I just added the onBeforeScrollStart code you have and it works great. Selected answer had unwanted side effects. Thanks. – Zaptree Mar 18 '13 at 17:46
    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);
                }    
            });
    
    Tim Kozak
    • 4,026
    • 39
    • 44
    • 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? – Molly Sep 04 '12 at 16:18
    • it was jquery.mobile-1.0a4 and iScroll v4.0 Beta 4. a can send you my libs – Tim Kozak Sep 05 '12 at 07:45
    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

    Saket Patel
    • 6,573
    • 1
    • 27
    • 36
    Sunil P
    • 41
    • 2
    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>
    
    Joe L.
    • 4,433
    • 1
    • 19
    • 14
    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);
                        });
    }
    
    tapin13
    • 51
    • 1
    • 5
    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();
    });
    
    Pablo Ezequiel Leone
    • 1,337
    • 17
    • 22
    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...

    Zennichimaro
    • 5,236
    • 6
    • 54
    • 78
    • This question was about iScroll 4 - your solution is made for the version 5. Anyways good to know. – Hexodus Aug 31 '13 at 07:59
    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

    g.e.manor
    • 526
    • 6
    • 12
    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">
    
    Community
    • 1
    • 1
    Krazer
    • 471
    • 7
    • 20
    0

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

    Sukesh Marla
    • 178
    • 11
    0

    What about, that works for me!:

    $('input, select').on('touchstart', function(e) {
        e.stopPropagation();
    });
    
    pkdkk
    • 3,905
    • 8
    • 44
    • 69
    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.

    diyism
    • 12,477
    • 5
    • 46
    • 46
    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.

    Anatolii Shuba
    • 4,614
    • 1
    • 16
    • 17
    0

    Check this. This fixed my issue

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

    In option I have selected

    click:false, preventDefaultException:{tagName:/.*/}
    
    A Paul
    • 8,113
    • 3
    • 31
    • 61
    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

    Daniele Segato
    • 12,314
    • 6
    • 62
    • 88
    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.

    Ragunath Jawahar
    • 19,513
    • 22
    • 110
    • 155
    Pete
    • 1