87 votes

Safari mobile : La méthode Javascript focus() sur un champ de saisie ne fonctionne qu'en cas de clic ?

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. Ainsi, à l'intérieur d'une fonction aléatoire (peu importe de quelle fonction il s'agit), j'ai cette ligne

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

Cela fonctionne parfaitement sur tous les ordinateurs de bureau, quels qu'ils soient.

Cependant, il ne fonctionne pas sur mon iPhone. Le champ n'est pas mis en évidence et le clavier ne s'affiche pas sur mon iPhone.

À des fins de test et pour vous montrer le problème, j'ai réalisé un échantillon 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);

Une idée de la raison pour laquelle le focus() ne fonctionne pas avec la fonction de temporisation de mon iPhone.

Pour voir l'exemple en direct, testez ce bidule 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, lorsqu'elle est "modifiée", mettre l'accent sur le champ de saisie et faire glisser le clavier sur l'iphone ou d'autres appareils mobiles. J'ai découvert que la fonction focus() est correctement activée mais que le clavier ne s'affiche pas. J'ai besoin que le clavier s'affiche.

83voto

Gregory Magarshak Points 448

En fait, les gars, il y a un moyen. J'ai eu beaucoup de mal à trouver cette solution pour [LINK REMOVED] (essayez sur un iPhone ou un iPad).

Fondamentalement, Safari sur les appareils à écran tactile est avare lorsqu'il s'agit de focus() des zones de texte. Même certains navigateurs de bureau s'en sortent mieux si vous le faites. click().focus() . Mais les concepteurs de Safari pour les appareils à écran tactile se sont rendu compte qu'il était ennuyeux pour les utilisateurs de voir le clavier s'afficher en permanence. Ils ont donc fait en sorte que le focus n'apparaisse que dans les conditions suivantes :

1) L'utilisateur a cliqué quelque part et focus() a été appelé pendant l'exécution de l'événement de clic. Si vous effectuez un appel AJAX, vous devez alors debe le faire de manière synchrone, comme avec l'outil obsolète (mais toujours disponible) $.ajax({async:false}) dans jQuery.

2) En outre, et cela m'a occupé pendant un certain temps focus() ne semble toujours pas fonctionner si une autre zone de texte est focalisée à ce moment-là. J'avais un bouton "Go" qui effectuait l'AJAX, j'ai donc essayé d'estomper la zone de texte sur la page d'accueil. touchstart du bouton "Go", mais cela a fait disparaître le clavier et a déplacé la fenêtre d'affichage avant que je n'aie eu le temps de cliquer sur le bouton "Go". Enfin, j'ai essayé d'estomper la zone de texte sur la page d'accueil. touchend du bouton Go, et cela a marché comme sur des roulettes !

En combinant les points 1 et 2, vous obtiendrez un résultat magique qui distinguera vos formulaires de connexion de tous les formulaires de connexion web pourris, en mettant l'accent sur vos champs de mot de passe et en les rendant plus naturels. Profitez-en ! :)

36voto

Raine Points 857

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

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)

}

Autres références : Désactiver le zoom automatique dans la balise de saisie "Texte" - Safari sur iPhone

6voto

WunderBart Points 1347

J'ai été confronté au même problème récemment. J'ai trouvé une solution qui fonctionne apparemment pour tous les appareils. Vous ne pouvez pas faire de focus asynchrone de manière programmatique mais vous pouvez commutateur la mise au point sur votre entrée cible lorsqu'une autre entrée est déjà mise au point. Donc, ce que vous devez faire, c'est créer, masquer, ajouter au DOM et mettre au point une entrée de type faux sur l'événement déclencheur et, lorsque l'action asynchrone est terminée, il suffit d'appeler à nouveau le focus sur l'entrée cible. Voici un exemple d'extrait - exécutez-le sur votre mobile.

éditer :

Voici un manipuler le même code . Apparemment, il n'est pas possible d'exécuter les extraits joints sur les 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>

4voto

istvan makary Points 41

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

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

Profitez de

3voto

martinmose Points 39

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 a résolu 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>

Il semble que vous utilisiez jQuery, donc je ne sais pas si la directive est utile.

Prograide.com

Prograide est une communauté de développeurs qui cherche à élargir la connaissance de la programmation au-delà de l'anglais.
Pour cela nous avons les plus grands doutes résolus en français et vous pouvez aussi poser vos propres questions ou résoudre celles des autres.

Powered by:

X