web-dev-qa-db-fra.com

Mobile Safari: La méthode focus () de Javascript sur inputfield ne fonctionne qu'avec click?

Je n'arrive pas à trouver une solution à ce problème.

J'ai un champ de saisie simple comme celui-ci.

<div class="search">
   <input type="text" value="y u no work"/>
</div>​

Et j'essaie de focus() à l'intérieur d'une fonction. Donc, à l'intérieur d'une fonction aléatoire (peu importe la fonction), j'ai cette ligne…

$('.search').find('input').focus();

Cela fonctionne parfaitement sur tous les postes de travail.

Cependant, cela ne fonctionne pas sur mon iPhone. Le champ ne se concentre pas et le clavier n'est pas affiché sur mon iPhone.

À des fins de test et pour vous montrer le problème, j'ai fait un exemple rapide:

$('#some-test-element').click(function() {
  $('.search').find('input').focus(); // works well on my iPhone - Keyboard slides in
});

setTimeout(function() {
  //alert('test'); //works
  $('.search').find('input').focus(); // doesn't work on my iPhone - works on Desktop
}, 5000);​

Aucune idée pourquoi la focus() ne fonctionnerait pas avec la fonction de délai d'attente sur mon iPhone.

Pour voir l'exemple en direct, testez ce violon sur votre iPhone. http://jsfiddle.net/Hc4sT/

Mise à jour:

J'ai créé exactement le même cas que celui auquel je suis actuellement confronté dans mon projet actuel.

J'ai une boîte de sélection qui devrait - une fois "modifiée" - régler le focus sur le champ de saisie et glisser le kexboard sur l'iphone ou d'autres appareils mobiles. J'ai découvert que le focus () est réglé correctement mais le clavier n'apparaît pas. J'ai besoin du clavier pour apparaître.

J'ai téléchargé les fichiers de test ici même http://cl.ly/1d210x1W3Y3W … Si vous testez cela sur l'iphone, vous pouvez voir que le clavier ne se glisse pas.

63
matt

En fait, les gars, il y a un moyen. J'ai eu du mal à comprendre cela http://forstartersapp.com (essayez-le sur iPhone ou iPad).

Fondamentalement, Safari sur les appareils à écran tactile est radin quand il s’agit de focus()ing champs de texte. Même certains navigateurs de bureau font mieux si vous faites click().focus(). Mais les concepteurs de Safari sur les appareils à écran tactile ont réalisé que le fait que le clavier continue de s’affaiblir gênait les utilisateurs. Ils ont donc mis l'accent uniquement sur les conditions suivantes:

1) L'utilisateur a cliqué quelque part et la fonction focus() a été appelée lors de l'exécution de l'événement click. Si vous effectuez un appel AJAX, vous devez le faire de manière synchrone, comme avec le modèle déconseillé (mais toujours disponible) $.ajax({async:false}) option dans jQuery.

2) En outre - et celui-ci m'a occupé pendant un certain temps - focus() ne semble toujours pas fonctionner si une autre zone de texte est active à ce moment-là. J'avais un bouton "Go" qui exécutait AJAX. J'ai donc essayé de rendre la zone de texte floue sur l'événement touchstart du bouton Go, mais cela a simplement fait disparaître le clavier et déplacé la fenêtre d'affichage avant que je puisse terminer. le clic sur le bouton Go. Enfin, j'ai essayé de rendre la zone de texte floue sur l'événement touchend du bouton Go, et cela a fonctionné à merveille!

Lorsque vous associez les symboles n ° 1 et n ° 2, vous obtenez un résultat magique qui distinguera vos formulaires de connexion de tous les formulaires de connexion Web de merde, en mettant en évidence les champs de votre mot de passe et en les faisant se sentir plus natifs. Prendre plaisir! :)

69

Une implémentation javascript native de la réponse de WunderBart.

Désactiver le zoom automatique en utilisant la taille de la police .

function onClick() {

  // create invisible dummy input to receive the focus first
  const fakeInput = document.createElement('input')
  fakeInput.setAttribute('type', 'text')
  fakeInput.style.position = 'absolute'
  fakeInput.style.opacity = 0
  fakeInput.style.height = 0
  fakeInput.style.fontSize = '16px' // disable auto zoom

  // you may need to append to another element depending on the browser's auto 
  // zoom/scroll behavior
  document.body.prepend(fakeInput)

  // focus so that subsequent async focus will work
  fakeInput.focus()

  setTimeout(() => {

    // now we can focus on the target input
    targetInput.focus()

    // cleanup
    fakeInput.remove()

  }, 1000)

}
6
Raine Revere

J'ai fait face au même problème récemment. J'ai trouvé une solution qui fonctionne apparemment pour tous les appareils. Vous ne pouvez pas faire la focalisation asynchrone par programme mais vous pouvez basculer vous concentrer sur votre entrée cible quand une autre entrée est déjà focalisée. Vous devez donc créer, masquer, ajouter à DOM & focus une entrée fausse sur un événement déclencheur et, une fois l'action asynchrone terminée, appelez simplement se concentrer à nouveau sur l'entrée cible. Voici un exemple d'extrait - exécutez-le sur votre mobile.

edit:

Voici un jouer avec le même code . Apparemment, vous ne pouvez pas exécuter d'extraits attachés sur des mobiles (ou je fais quelque chose de mal).

var $triggerCheckbox = $("#trigger-checkbox");
var $targetInput = $("#target-input");

// Create fake & invisible input
var $fakeInput = $("<input type='text' />")
  .css({
    position: "absolute",
    width: $targetInput.outerWidth(), // zoom properly (iOS)
    height: 0, // hide cursor (font-size: 0 will zoom to quarks level) (iOS)
    opacity: 0, // make input transparent :]
  });

var delay = 2000; // That's crazy long, but good as an example

$triggerCheckbox.on("change", function(event) {
  // Disable input when unchecking trigger checkbox (presentational purpose)
  if (!event.target.checked) {
    return $targetInput
      .attr("disabled", true)
      .attr("placeholder", "I'm disabled");
  }

  // Prepend to target input container and focus fake input
  $fakeInput.prependTo("#container").focus();

  // Update placeholder (presentational purpose)
  $targetInput.attr("placeholder", "Wait for it...");

  // setTimeout, fetch or any async action will work
  setTimeout(function() {

    // Shift focus to target input
    $targetInput
      .attr("disabled", false)
      .attr("placeholder", "I'm alive!")
      .focus();

    // Remove fake input - no need to keep it in DOM
    $fakeInput.remove();
  }, delay);
});
label {
  display: block;
  margin-top: 20px;
}

input {
  box-sizing: border-box;
  font-size: inherit;
}

#container {
  position: relative;
}

#target-input {
  width: 250px;
  padding: 10px;
}
<script src="https://ajax.googleapis.com/ajax/libs/jquery/1.9.1/jquery.min.js"></script>
<div id="container">
  <input type="text" id="target-input" placeholder="I'm disabled" />

  <label>
    <input type="checkbox" id="trigger-checkbox" />
    focus with setTimetout
   </label>
</div>
5
WunderBart

J'ai réussi à le faire fonctionner avec le code suivant:

event.preventDefault();
timeout(function () {
    $inputToFocus.focus();
}, 500);

J'utilise AngularJS et j'ai donc créé une directive qui résout mon problème:

Directive:

angular.module('directivesModule').directive('focusOnClear', [
    '$timeout',
    function (timeout) {
        return {
            restrict: 'A',
            link: function (scope, element, attrs) {
                var id = attrs.focusOnClear;
                var $inputSearchElement = $(element).parent().find('#' + id);
                element.on('click', function (event) {
                    event.preventDefault();
                    timeout(function () {
                        $inputSearchElement.focus();
                    }, 500);
                });
            }
        };
    }
]);

Comment utiliser la directive:

<div>
    <input type="search" id="search">
    <i class="icon-clear" ng-click="clearSearchTerm()" focus-on-clear="search"></i>
</div>

On dirait que vous utilisez jQuery, donc je ne sais pas si la directive peut vous aider.

2
martinmose

J'ai un formulaire de recherche avec une icône qui efface le texte lorsque vous cliquez dessus. Cependant, le problème (sur mobile et tablettes) était que le clavier s'effondrerait/se masquerait, car l'événement click supprimé focus était supprimé de input.

text search input with close icon

objectif: après avoir effacé le formulaire de recherche (cliquer/taper sur l'icône x) garder le clavier visible!

Pour ce faire, appliquez stopPropagation() à l'événement de la manière suivante:

function clear ($event) {
    $event.preventDefault();
    $event.stopPropagation();
    self.query = '';
    $timeout(function () {
        document.getElementById('sidebar-search').focus();
    }, 1);
}

Et le formulaire HTML:

<form ng-controller="SearchController as search"
    ng-submit="search.submit($event)">
        <input type="search" id="sidebar-search" 
            ng-model="search.query">
                <span class="glyphicon glyphicon-remove-circle"
                    ng-click="search.clear($event)">
                </span>
</form>
2
DeBraid

MISE À JOUR

J'ai aussi essayé cela, mais en vain:

$(document).ready(function() {
$('body :not(.wr-dropdown)').bind("click", function(e) {
    $('.test').focus();
})
$('.wr-dropdown').on('change', function(e) {
    if ($(".wr-dropdow option[value='/search']")) {
        setTimeout(function(e) {
            $('body :not(.wr-dropdown)').trigger("click");
        },3000)         
    } 
}); 

});

Je ne comprends pas pourquoi vous dites que cela ne fonctionne pas parce que votre JSFiddle fonctionne très bien, mais voici ma suggestion quand même ...

Essayez cette ligne de code dans votre fonction SetTimeOut sur votre événement click:

document.myInput.focus();

myInput est corrélé à l'attribut name de la balise d'entrée.

<input name="myInput">

Et utilisez ce code pour brouiller le champ:

document.activeElement.blur();
1
Alex

Cette solution fonctionne bien, j'ai testé sur mon téléphone:

document.body.ontouchend = function() { document.querySelector('[name="name"]').focus(); };

prendre plaisir

1
istvan makary