收录日期:2019/05/24 23:34:09 时间:2013-03-25 19:58:44 标签:javascript,jquery,jquery-ui

I have setup a jQuery UI modal dialog to display when a user clicks a link. There are two textboxes (I only show the code for 1 for brevity) in that dialog div tag and it is changed to be a jQuery UI DatePicker textbox that reacts on focus.

The problem is that the jQuery UI dialog('open') somehow triggers the first textbox to have focus, which then triggers the datepicker calendar to open immediately.

So I am looking for a way to prevent the focus from happening automatically.

<div><a id="lnkAddReservation" href="#">Add reservation</a></div>

<div id="divNewReservation" style="display:none" title="Add reservation">
    <table>
        <tr>
            <th><asp:Label AssociatedControlID="txtStartDate" runat="server" Text="Start date" /></th>
            <td>
                <asp:TextBox ID="txtStartDate" runat="server" CssClass="datepicker" />
            </td>
        </tr>
    </table>

    <div>
        <asp:Button ID="btnAddReservation" runat="server" OnClick="btnAddReservation_Click" Text="Add reservation" />
    </div>
</div>

<script type="text/javascript">
    $(document).ready(function() {
        var dlg = $('#divNewReservation');
        $('.datepicker').datepicker({ duration: '' });
        dlg.dialog({ autoOpen:false, modal: true, width:400 });
        $('#lnkAddReservation').click(function() { dlg.dialog('open'); return false; });
        dlg.parent().appendTo(jQuery("form:first"));
    });
</script>

jQuery UI 1.10.0 Changelog lists ticket 4731 as being fixed.

Looks like focusSelector was not implemented, but a cascading search for various elements was used instead. From the ticket:

Extend autofocus, starting with [autofocus], then :tabbable content, then buttonpane, then close button, then dialog

So, mark an element with the autofocus attribute and that is the element that should get the focus:

<input autofocus>

In the documentation, the focus logic is explained (just under the table of contents, under the title 'Focus'):

Upon opening a dialog, focus is automatically moved to the first item that matches the following:

  1. The first element within the dialog with the autofocus attribute
  2. The first :tabbable element within the dialog's content
  3. The first :tabbable element within the dialog's buttonpane
  4. The dialog's close button
  5. The dialog itself

Add a hidden span above it, use ui-helper-hidden-accessible to make it hidden by absolute positioning. I know you have that class because you are using dialog from jquery-ui and it's in jquery-ui.

<span class="ui-helper-hidden-accessible"><input type="text"/></span>

In jQuery UI >= 1.10.2, you can replace the _focusTabbable prototype method by a placebo function:

$.ui.dialog.prototype._focusTabbable = $.noop;

Fiddle

This will affect all dialogs in the page without requiring to edit each one manually.

The original function does nothing but setting the focus to the first element with autofocus attribute / tabbable element / or falling back to the dialog itself. As its use is just setting focus on an element, there should be no problem replacing it by a noop.

I found the following code the jQuery UI dialog function for open.

c([]).add(d.find(".ui-dialog-content :tabbable:first")).add(d.find(".ui-dialog-buttonpane :tabbable:first")).add(d).filter(":first").focus();

You can either workaround the jQuery behaviour or change the behaviour.

tabindex -1 works as a workaround.

Starting from jQuery UI 1.10.0, you can choose which input element to focus on by using the HTML5 attribute autofocus.

All you have to do is create a dummy element as your first input in the dialog box. It will absorb the focus for you.

<input type="hidden" autofocus="autofocus" />

This has been tested in Chrome, Firefox and Internet Explorer (all latest versions) on February 7, 2013.

http://jqueryui.com/upgrade-guide/1.10/#added-ability-to-specify-which-element-to-focus-on-open

Set the tabindex of the input to -1, and then set dialog.open to restore tabindex if you need it later:

$(function() {
    $( "#dialog-message" ).dialog({
        modal: true,
        width: 500,
        autoOpen: false,
        resizable: false,
        open: function()
        {
            $( "#datepicker1" ).attr("tabindex","1");
            $( "#datepicker2" ).attr("tabindex","2");
        }
    });
});

My workaround:

open: function(){
  jQuery('input:first').blur();
  jQuery('#ui-datepicker-div').hide();
},  

Simple workaround:

Just create a invisible element with tabindex=1 ... This will not focus the datepicker ...

eg.:

<a href="" tabindex="1"></a>
...
Here comes the input element

I had content that was longer than the dialog. On open, the dialog would scoll to the first :tabbable which was at the bottom. Here was my fix.

$("#myDialog").dialog({
   ...
   open: function(event, ui) { $(this).scrollTop(0); }
});

Just figured this out while playing around.

I found with these solutions to remove focus, caused the ESC key to stop working (ie close the dialog) when first going into the Dialog.

If the dialog opens and you immediately press ESC, it won't close the dialog (if you have that enabled), because the focus is on some hidden field or something, and it is not getting keypress events.

The way I fixed it was to add this to the open event to remove the focus from the first field instead:

$('#myDialog').dialog({
    open: function(event,ui) {
        $(this).parent().focus();
    }
});

This sets focus to the dialog box, which is not visible, and then the ESC key works.

Here is the solution I implemented after reading through jQuery UI ticket #4731, originally posted by slolife as a response to another answer. (The ticket was also created by him.)

First, in whatever method you use to apply autocompletes to the page, add the following line of code:

$.ui.dialog.prototype._focusTabbable = function(){};

That disables jQuery's "auto-focus" behavior. To ensure that your site continues to be broadly accessible, wrap your dialog creation methods so that additional code can be added, and add a call to focus the first input element:

function openDialog(context) {

    // Open your dialog here

    // Usability for screen readers.  Focus on an element so that screen readers report it.
    $("input:first", $(context)).focus();

}

To further address accessibility when autocomplete options are selected via keyboard, we override jQuery UI's "select" autocomplete callback and add some additional code to ensure the textElement does not lose focus in IE 8 after making a selection.

Here is the code we use to apply autocompletes to elements:

$.fn.applyAutocomplete = function () {

    // Prevents jQuery dialog from auto-focusing on the first tabbable element.
    // Make sure to wrap your dialog opens and focus on the first input element
    // for screen readers.
    $.ui.dialog.prototype._focusTabbable = function () { };

    $(".autocomplete", this)
        .each(function (index) {

            var textElement = this;

            var onSelect = $(this).autocomplete("option", "select");
            $(this).autocomplete("option", {
                select: function (event, ui) {
                    // Call the original functionality first
                    onSelect(event, ui);

                    // We replace a lot of content via AJAX in our project.
                    // This ensures proper copying of values if the original element which jQuery UI pointed to
                    // is replaced.
                    var $hiddenValueElement = $("#" + $(textElement).attr('data-jqui-acomp-hiddenvalue'));
                    if ($hiddenValueElement.attr("value") != ui.item.value) {
                        $hiddenValueElement.attr("value", ui.item.value);
                    }

                    // Replace text element value with that indicated by "display" if any
                    if (ui.item.display)
                        textElement.value = ui.item.display;

                    // For usability purposes.  When using the keyboard to select from an autocomplete, this returns focus to the textElement.
                    $(textElement).focus();

                    if (ui.item.display)
                        return false;

                }
            });
        })
        // Set/clear data flag that can be checked, if necessary, to determine whether list is currently dropped down
        .on("autocompleteopen", function (event, ui) {
            $(event.target).data().autocompleteIsDroppedDown = true;
        })
        .on("autocompleteclose", function (event, ui) {
            $(event.target).data().autocompleteIsDroppedDown = false;
        });

    return this;
}

This can be a browser behavior not jQuery plugin issue. Have you tried removing the focus programmatically after you open the popup.

$('#lnkAddReservation').click(function () {
    dlg.dialog('open');

    // you may want to change the selector below
    $('input,textarea,select').blur();

    return false;
});

Haven't tested that but should work ok.

I'd the same issue and solved it by inserting an empty input before the datepicker, that steals the focus every time the dialog is opened. This input is hidden on every opening of the dialog and shown again on closing.

Well, it is cool that nobody found the solution for now, but it looks like I have something for you. The bad news is that the dialog grabs focus in any case even if no inputs and links are inside. I use the dialog as a tooltip and definitely need focus stay in the original element. Here is my solution:

use option [autoOpen: false]

$toolTip.dialog("widget").css("visibility", "hidden"); 
$toolTip.dialog("open");
$toolTip.dialog("widget").css("visibility", "visible");

While the dialog invisible, the focus is not set anywhere and stay in the original place. It works for tooltips with just a plain text, but not tested for more functional dialogs where it may be important to have dialog visible on opening moment. Probably will work fine in any case.

I understand that the original post was just to avoid getting focus on the first element, but you can easily decide where the focus should be after the dialog is opened (after my code).

Tested in IE, FF and Chrome.

Hopefully this will help somebody.

I have a similar problem. I open an error dialog when validation fails and it grabs the focus, just like Flugan shows it in his answer. The problem is that even if no element inside the dialog is tabbable, the dialog itself is still focused. Here is the original unminified code from jquery-ui-1.8.23\js\jquery.ui.dialog.js:

// set focus to the first tabbable element in the content area or the first button
// if there are no tabbable elements, set focus on the dialog itself
$(self.element.find(':tabbable').get().concat(
  uiDialog.find('.ui-dialog-buttonpane :tabbable').get().concat(
    uiDialog.get()))).eq(0).focus();

The comment is theirs!

This is really bad for me for several reasons. The most annoying thing is that the first reaction of the user is to hit the backspace to delete the last character, but instead (s)he is prompted to leave the page, because the backspace is hit outside an input control.

I found that the following workaround works pretty good for me:

jqueryFocus = $.fn.focus;
$.fn.focus = function (delay, fn) {
  jqueryFocus.apply(this.filter(':not(.ui-dialog)'), arguments);
};

I was looking around for a different issue but same cause. The issue is that the dialog set focus to the first <a href="">.</a> it finds. So if you have a lot of text in your dialog and scroll bars appear you could have the situation where the scroll bar will be scrolled to the bottom. I believe this also fixes the first persons question. Although the others do as well.

The simple easy to understand fix. <a id="someid" href="#">.</a> as the first line in your dialog div.

EXAMPLE:

 <div id="dialogdiv" title="some title">
    <a id="someid" href="#">.</a>
    <p>
        //the rest of your stuff
    </p>
</div>

Where your dialog is initiated

$(somediv).dialog({
        modal: true,
        open: function () { $("#someid").hide(); otherstuff or function },
        close: function () { $("#someid").show(); otherstuff or function }
    });

The above will have nothing focused and the scroll bars will remain at the top where it belongs. The <a> gets focus but is then hidden. So the overall effect is the desired effect.

I know this is an old thread but as for as the UI docs there is no fix to this. This does not require blur or focus to work. Not sure if it is the most elegant. But it just makes sense and easy to explain to anyone.

If you only have one field in the form of Jquery dialog and it is the one that needs Datepicker, alternatively, you can just set focus on dialog Close (cross) button in dialog's title bar:

$('.ui-dialog-titlebar-close').focus();

Call this AFTER dialog was initialized, e.g.:

$('#yourDialogId').dialog();
$('.ui-dialog-titlebar-close').focus();

Because close button is rendered after the .dialog() is called.

I got the same problem.

The workaround I did is add the dummy textbox at the top of the dialog container.

<input type="text" style="width: 1px; height: 1px; border: 0px;" />

As mentioned, this is a known bug with jQuery UI and should be fixed relatively soon. Until then...

Here's another option, so you don't have to mess with tabindex:

Disable the datepicker temporarily until the dialog box opens:

dialog.find(".datepicker").datepicker("disable");
dialog.dialog({
    "open": function() {$(this).find(".datepicker").datepicker("enable");},
});

Works for me.

Duplicate question: How to blur the first form input at the dialog opening

To expand on some of the previous answers (and ignoring the ancillary datepicker aspect), if you want to prevent the focus() event from focusing the first input field when your dialog opens, try this:

$('#myDialog').dialog(
    { 'open': function() { $('input:first-child', $(this)).blur(); }
});

I had a similar problem and solved it by focusing on the dialog after open:

var $dialog = $("#pnlFiltros")
    .dialog({
        autoOpen: false,
        hide: "puff",                   
        width: dWidth,
        height: 'auto',
        draggable: true,
        resizable: true,
        closeOnScape : true,
        position: [x,y]                    
    });
$dialog.dialog('open');
$("#pnlFiltros").focus(); //focus on the div being dialogued (is that a word?)

But in my case the first element is an anchor, so I don't know if in your case that will leave the datepicker opened.

EDIT: only works on IE

find in jquery.ui.js

d.find(".ui-dialog-buttonpane :tabbable").get().concat(d.get()))).eq(0).focus(); 

and replace with

d.find(".ui-dialog-buttonpane :tabbable").get().concat(d.get()))).eq(-1).focus();

In my opinion this solution is very nice:

$("#dialog").dialog({
    open: function(event, ui) {
        $("input").blur();
    }
});

Found here: unable-to-remove-autofocus-in-ui-dialog

jQuery 1.9 is released and there does not appear to be a fix. Attempting to prevent focus of the first text box by some of the suggested methods is not working in 1.9. I think beccause the methods attempt to blur focus or move focus occur AFTER the text box in the dialog has already gained focus and done its dirty work.

I can't see anything in the API documentation that makes me think that anything has changed in terms of expected functionality. Off to add an opener button...

I had similar problem. On my page first input is text box with jQuery UI calendar. Second element is button. As date already have value, I set focus on button, but first add trigger for blur on text box. This solve problem in all browsers and probably in all version of jQuery. Tested in version 1.8.2.

<div style="padding-bottom: 30px; height: 40px; width: 100%;">
@using (Html.BeginForm("Statistics", "Admin", FormMethod.Post, new { id = "FormStatistics" }))
{
    <label style="float: left;">@Translation.StatisticsChooseDate</label>
    @Html.TextBoxFor(m => m.SelectDate, new { @class = "js-date-time",  @tabindex=1 })
    <input class="button gray-button button-large button-left-margin text-bold" style="position:relative; top:-5px;" type="submit" id="ButtonStatisticsSearchTrips" value="@Translation.StatisticsSearchTrips"  tabindex="2"/>
}

<script type="text/javascript">
$(document).ready(function () {        
    $("#SelectDate").blur(function () {
        $("#SelectDate").datepicker("hide");
    });
    $("#ButtonStatisticsSearchTrips").focus();

});   

This is really important for smartphones and tablets because the keyboard comes up when an input has the focus. This is what I've done, add this input at the beginning of the div:

<input type="image" width="1px" height="1px"/>

Doesn't work with size 0px. I guess it's even better with a real transparent image, either .png or .gif but I haven't tried.

Working fine so far in iPad.

You can Add this :

...

dlg.dialog({ autoOpen:false,
modal: true, 
width: 400,
open: function(){                  // There is new line
  $("#txtStartDate").focus();
  }
});

...

as first input : <input type="text" style="position:absolute;top:-200px" />