8

I have run into an infuriating bug on Safari for iPad that I cannot fix.

Architecture:

  • backbone 0.9.9
  • jquery 1.7.2
  • jquery mobile 1.3.1

User agent:

  • iOS 5.1.1 (iPad)
  • Safari 5.1 mobile
  • full user agent string: Mozilla/5.0 (iPad; CUP OS 5_1_1 like Mac OS X) AppleWebKit/534.46 (KHTML, like Gecko) Version/5.1 Mobile/9B206 Safari/7534.48.3

I have a 10 instances of the same View, each of which has a nested View that contains a textarea element. For some reason when you tap the textarea, it randomly does not focus. I've read that Safari mobile is wonky when you attempt to trigger focus events that don't come from a tap/click event, but this is a direct tap and it still does not focus reliably. Here's the stripped-down code for the views:

var ParentView = Backbone.View.extend({
    render: function() {
        this.$el.html("<div class='textarea-container'></div>");
        this.textareaView = new TextareaView({
            el: this.$el.find('.textarea-container')
        });
        this.textareaView.render();
    }
};
var TextareaView = Backbone.View.extend({
    events: {
        'tap .my-textarea': 'handleTextareaTap'
    },
    render: function() {
        this.$el.html('<textarea rows="4" cols="80" class='my-textarea'></textarea>');
    },
    handleTextareaTap: function(event) {
        console.log('TAPPED');
    }
};
var i = 0;
while ( i < 10 ) {
    var view = new ParentView();
    view.render();
    $(body).append(view.$el);
    i++;
}

The tap event handler fires 100% of the time. The console correctly displays "TAPPED" each time. But most of the time, the user agent fails focus in the textarea. I added the following line into the TextareaView to see exactly which events Safari is firing and in what order:

var TextareaView = Backbone.View.extend({
    render: function() {
        this.$el.html('<textarea rows="4" cols="80" class='my-textarea'></textarea>');
        this.$el.find('.my-textarea').on('blur change click contextmenu copy cut dblclick focus focusin focusout hashchange keydown keypress keyup load mousedown mouseenter mouseleave mousemove mouseout mouseover mouseup mousewheel paste reset scroll select submit textinput unload wheel tap touch scrollstart scrollstop swipe swipeleft swiperight vclick vmousecancel vmousedown vmousemove vmouseout vmouseover vmouseup touchstart touchend touchmove touchcancel', function(event) {
            console.log(event.type);
        }
    },
};

Here's the event order I get when the textarea focuses correctly: touchstart, vmouseover, vmousedown, touchend, vmouseup, vclick, tap, vmouseout, mousemove, mousedown, focusin, focus, mouseup, click, focusout, blur

Here's the event order I get when the textarea fails to focus: touchstart, vmouseover, vmousedown, touchend, vmouseup, vclick, tap, vmouseout, mousemove

For some reason the events after mousemove fail to fire. I've tried manually triggering these events as well, but the textarea element still does not focus nor does the keyboard pop up, e.g.:

var TextareaView = Backbone.View.extend({
    handleTextareaTap: function(event) {
        // This still doesn't work:
        this.$el.find('.my-textarea').trigger('focus');
        // Neither does waiting for the synthesized WebKit events to fire:
        var _this = this;
        setTimeout(function(){
           _this.$el.find('.my-textarea').trigger('focus');
        }, 1000);
    }
};

I've poured over Apple's event handler documentation to no avail, and I can't find any bug reports relating to this in any of the repos on github.

Two other weird behaviors that I do not understand:

  1. the first instance of the textarea always works correctly
  2. the textarea focuses despite a blur event being called

Any insight would be appreciated.

Cheers,

biegel
  • 570
  • 5
  • 12
  • Did you ever find a solution to this problem? I am facing a similar issue and curious how you solved it. – alnafie Jul 02 '14 at 08:04
  • Your render function (here anyway) uses single-quotes around the class name, where it should be using double-quotes. Was that a typo when your wrote the question, or is that how your code is written? – John Oct 05 '14 at 17:07
  • I never did find a solution, and, as often happens, the project scope changed :-) We're no longer using this library anymore. – biegel Nov 10 '14 at 20:02

1 Answers1

0

Try adding this directly after the .focus()

.parent().appendTo($'form:first');

When a page is rendered it lives in the DOM, if you modify an element in the DOM it can move out of the DOM after modification, then you can't get back to it. The code above shifts it back in to the DOM.

Fingers crossed your text area focus will work after the modded element is shifted back in.

have a look at this to see it explained better.

jQuery modal form dialog postback problems

..and..

$("#dialog").parent().appendTo($("form:first"));

Community
  • 1
  • 1
FlemGrem
  • 814
  • 4
  • 9