Question Comment mettre l'accent sur le champ de saisie?


Quelle est la «manière angulaire» de mettre l'accent sur le champ de saisie dans AngularJS?

Exigences plus spécifiques:

  1. Lorsqu'un Modal est ouvert, mettre l'accent sur un prédéfini <input> à l'intérieur de ce modal.
  2. À chaque fois <input> devient visible (par exemple en cliquant sur un bouton), mettez le focus dessus.

J'ai essayé d'atteindre la première exigence avec autofocus, mais cela ne fonctionne que lorsque le Modal est ouvert pour la première fois, et seulement dans certains navigateurs (par exemple, dans Firefox, cela ne fonctionne pas).

Toute aide serait appréciée.


713
2018-02-12 13:08


origine


Réponses:


  1. Quand un Modal est ouvert, réglez le focus sur un <input> prédéfini à l'intérieur de ce Modal.

Définissez une directive et faites en sorte que $ surveille une propriété / un déclencheur pour qu'il sache quand il faut focaliser l'élément:

Name: <input type="text" focus-me="shouldBeOpen">

app.directive('focusMe', ['$timeout', '$parse', function ($timeout, $parse) {
    return {
        //scope: true,   // optionally create a child scope
        link: function (scope, element, attrs) {
            var model = $parse(attrs.focusMe);
            scope.$watch(model, function (value) {
                console.log('value=', value);
                if (value === true) {
                    $timeout(function () {
                        element[0].focus();
                    });
                }
            });
            // to address @blesh's comment, set attribute value to 'false'
            // on blur event:
            element.bind('blur', function () {
                console.log('blur');
                scope.$apply(model.assign(scope, false));
            });
        }
    };
}]);

Plunker

Le $ timeout semble être nécessaire pour donner le temps modal à rendre.

'2.' Chaque fois que <entrée> devient visible (par exemple en cliquant sur un bouton), réglez-le sur.

Créer une directive essentiellement comme celle ci-dessus. Regardez une propriété d'étendue, et quand elle devient vraie (définissez-la dans votre gestionnaire ng-click), exécutez element[0].focus(). Selon votre cas d'utilisation, vous pouvez ou non avoir besoin d'un timeout $ pour celui-ci:

<button class="btn" ng-click="showForm=true; focusInput=true">show form and
 focus input</button>
<div ng-show="showForm">
  <input type="text" ng-model="myInput" focus-me="focusInput"> {{ myInput }}
  <button class="btn" ng-click="showForm=false">hide form</button>
</div>

app.directive('focusMe', function($timeout) {
  return {
    link: function(scope, element, attrs) {
      scope.$watch(attrs.focusMe, function(value) {
        if(value === true) { 
          console.log('value=',value);
          //$timeout(function() {
            element[0].focus();
            scope[attrs.focusMe] = false;
          //});
        }
      });
    }
  };
});

Plunker


Mise à jour 7/2013: J'ai vu quelques personnes utiliser mes directives d'origine isolate scope et ont ensuite des problèmes avec les champs d'entrée intégrés (c'est-à-dire, un champ de saisie dans le modal). Une directive sans nouvelle portée (ou éventuellement une nouvelle portée d'enfant) devrait soulager une partie de la douleur. Donc, au-dessus j'ai mis à jour la réponse pour ne pas utiliser les étendues isolées. Voici la réponse originale:

Réponse originale pour 1., en utilisant une portée isolate:

Name: <input type="text" focus-me="{{shouldBeOpen}}">

app.directive('focusMe', function($timeout) {
  return {
    scope: { trigger: '@focusMe' },
    link: function(scope, element) {
      scope.$watch('trigger', function(value) {
        if(value === "true") { 
          $timeout(function() {
            element[0].focus(); 
          });
        }
      });
    }
  };
});

Plunker.

Réponse originale pour 2., en utilisant une portée isolate:

<button class="btn" ng-click="showForm=true; focusInput=true">show form and
 focus input</button>
<div ng-show="showForm">
  <input type="text" focus-me="focusInput">
  <button class="btn" ng-click="showForm=false">hide form</button>
</div>

app.directive('focusMe', function($timeout) {
  return {
    scope: { trigger: '=focusMe' },
    link: function(scope, element) {
      scope.$watch('trigger', function(value) {
        if(value === true) { 
          //console.log('trigger',value);
          //$timeout(function() {
            element[0].focus();
            scope.trigger = false;
          //});
        }
      });
    }
  };
});

Plunker.

Comme nous devons réinitialiser la propriété trigger / focusInput dans la directive, '=' est utilisé pour la liaison de données bidirectionnelle. Dans la première directive, «@» était suffisant. Notez également que lorsque vous utilisez '@', nous comparons la valeur de déclenchement à "true" car @ entraîne toujours une chaîne.


548
2018-02-12 16:23



(EDIT: J'ai ajouté une solution mise à jour sous cette explication)

Mark Rajcok est l'homme ... et sa réponse est une réponse valable, mais a avait un défaut (désolé Mark) ...

... Essayez d'utiliser le booléen pour vous concentrer sur l'entrée, puis brouillez l'entrée, puis essayez de l'utiliser pour recentrer l'entrée. Cela ne fonctionnera que si vous réinitialisez le booléen à false, puis $ digest, puis le réinitialisez à true. Même si vous utilisez une comparaison de chaînes dans votre expression, vous serez obligé de changer la chaîne en autre chose, $ digest, puis de la modifier. (Cela a été résolu avec le gestionnaire d'événements flou.)

Donc je propose cette solution alternative:

Utilisez un événement, la caractéristique oubliée d'Angular.

JavaScript aime les événements après tout. Les événements sont intrinsèquement couplés, et mieux encore, vous évitez d'ajouter $ watch à votre $ digest.

app.directive('focusOn', function() {
   return function(scope, elem, attr) {
      scope.$on(attr.focusOn, function(e) {
          elem[0].focus();
      });
   };
});

Alors maintenant vous pouvez l'utiliser comme ceci:

<input type="text" focus-on="newItemAdded" />

et puis n'importe où dans votre application ...

$scope.addNewItem = function () {
    /* stuff here to add a new item... */

    $scope.$broadcast('newItemAdded');
};

C'est génial parce que vous pouvez faire toutes sortes de choses avec quelque chose comme ça. Pour un, vous pourriez attacher à des événements qui existent déjà. D'autre part, vous commencez à faire quelque chose de malin en faisant en sorte que différentes parties de votre application publient des événements auxquels d'autres parties de votre application peuvent s'abonner.

Quoi qu'il en soit, ce genre de chose me crie "événementiel". Je pense qu'en tant que développeurs Angular, nous essayons vraiment de marteler des chevilles en forme de champ d'action dans des trous de forme d'événement.

Est-ce la meilleure solution? Je ne sais pas. Ses une Solution.


Solution mise à jour

Après le commentaire de @ ShimonRachlenko ci-dessous, j'ai changé ma méthode de faire cela légèrement. Maintenant, j'utilise une combinaison d'un service et d'une directive qui gère un événement "dans les coulisses":

Autre que cela, c'est le même principe décrit ci-dessus.

Voici une démo rapide

Usage

<input type="text" focus-on="focusMe"/>
app.controller('MyCtrl', function($scope, focus) {
    focus('focusMe');
});

La source

app.directive('focusOn', function() {
   return function(scope, elem, attr) {
      scope.$on('focusOn', function(e, name) {
        if(name === attr.focusOn) {
          elem[0].focus();
        }
      });
   };
});

app.factory('focus', function ($rootScope, $timeout) {
  return function(name) {
    $timeout(function (){
      $rootScope.$broadcast('focusOn', name);
    });
  }
});

255
2017-08-18 03:30



J'ai trouvé que certaines des autres réponses étaient trop compliquées quand tout ce dont vous avez vraiment besoin c'est

app.directive('autoFocus', function($timeout) {
    return {
        restrict: 'AC',
        link: function(_scope, _element) {
            $timeout(function(){
                _element[0].focus();
            }, 0);
        }
    };
});

l'utilisation est

<input name="theInput" auto-focus>

Nous utilisons le timeout pour laisser des choses dans le dom, même s'il est nul, il attend au moins cela - de cette façon cela fonctionne dans les modaux et autres joyeusetés


231
2018-01-01 02:25



HTML a un attribut autofocus.

<input type="text" name="fname" autofocus>

http://www.w3schools.com/tags/att_input_autofocus.asp


82
2017-09-29 12:43



Vous pouvez également utiliser la fonctionnalité jqlite intégrée dans angulaire.

angular.element('.selector').trigger('focus');


56
2017-12-11 08:35



Cela fonctionne bien et une manière angulaire de concentrer le contrôle des entrées

angular.element('#elementId').focus()

Bien que ce ne soit pas une manière purement angulaire de faire la tâche, la syntaxe suit un style angulaire. Jquery joue indirectement un rôle et accède directement à DOM en utilisant Angular (jQLite => JQuery Light).

Si nécessaire, ce code peut facilement être placé dans une directive angulaire simple où l'élément est directement accessible.


49
2017-08-11 07:10



Je ne pense pas que $ timeout soit un bon moyen de focaliser l'élément sur la création. Voici une méthode utilisant la fonctionnalité angulaire intégrée, creusée à partir des profondeurs troubles des docs angulaires. Remarquez comment l'attribut "link" peut être divisé en "pre" et "post", pour les fonctions pré-link et post-link.

Exemple de travail: http://plnkr.co/edit/Fj59GB

// this is the directive you add to any element you want to highlight after creation
Guest.directive('autoFocus', function() {
    return {
        link: {
            pre: function preLink(scope, element, attr) {
                console.debug('prelink called');
                // this fails since the element hasn't rendered
                //element[0].focus();
            },
            post: function postLink(scope, element, attr) {
                console.debug('postlink called');
                // this succeeds since the element has been rendered
                element[0].focus();
            }
        }
    }
});
<input value="hello" />
<!-- this input automatically gets focus on creation -->
<input value="world" auto-focus />

Documents complets de la Directive AngularJS: https://docs.angularjs.org/api/ng/service/$compile


30
2018-05-28 19:07



J'ai écrit une directive de mise au point contraignante bidirectionnelle, tout comme le modèle récemment.

Vous utilisez une directive de mise au point comme celle-ci:

<input focus="someFocusVariable">

Si vous faites en sorte que la variable d'étendue FocusVariable soit vraie quelque part dans votre contrôleur, l'entrée a le focus. Et si vous "brouillez" votre entrée, someFocusVariable est défini sur false. C'est comme la première réponse de Mark Rajcok mais avec une liaison bidirectionnelle.

Voici la directive:

function Ctrl($scope) {
  $scope.model = "ahaha"
  $scope.someFocusVariable = true; // If you want to focus initially, set this to true. Else you don't need to define this at all.
}

angular.module('experiement', [])
  .directive('focus', function($timeout, $parse) {
    return {
      restrict: 'A',
      link: function(scope, element, attrs) {
          scope.$watch(attrs.focus, function(newValue, oldValue) {
              if (newValue) { element[0].focus(); }
          });
          element.bind("blur", function(e) {
              $timeout(function() {
                  scope.$apply(attrs.focus + "=false"); 
              }, 0);
          });
          element.bind("focus", function(e) {
              $timeout(function() {
                  scope.$apply(attrs.focus + "=true");
              }, 0);
          })
      }
    }
  });

Usage:

<div ng-app="experiement">
  <div ng-controller="Ctrl">
    An Input: <input ng-model="model" focus="someFocusVariable">
    <hr>
        <div ng-click="someFocusVariable=true">Focus!</div>  
        <pre>someFocusVariable: {{ someFocusVariable }}</pre>
        <pre>content: {{ model }}</pre>
  </div>
</div>

Voici le violon:

http://fiddle.jshell.net/ubenzer/9FSL4/8/


18
2017-07-19 06:49



Voici ma solution originale:

plunker

var app = angular.module('plunker', []);
app.directive('autoFocus', function($timeout) {
    return {
        link: function (scope, element, attrs) {
            attrs.$observe("autoFocus", function(newValue){
                if (newValue === "true")
                    $timeout(function(){element[0].focus()});
            });
        }
    };
});

Et le HTML:

<button ng-click="isVisible = !isVisible">Toggle input</button>
<input ng-show="isVisible" auto-focus="{{ isVisible }}" value="auto-focus on" />

Ce qu'il fait:

Il focalise l'entrée lorsqu'elle devient visible avec ng-show. Pas d'utilisation de $ watch ou $ ici.


17
2018-06-11 20:58



Pour ceux qui utilisent Angular avec le plugin Bootstrap:

http://angular-ui.github.io/bootstrap/#/modal

Vous pouvez vous accrocher dans le opened promesse de l'instance modale:

modalInstance.opened.then(function() {
        $timeout(function() {
            angular.element('#title_input').trigger('focus');
        });
    });

modalInstance.result.then(function ( etc...

10
2018-03-03 15:32



Au lieu de créer votre propre directive, il est possible d'utiliser simplement les fonctions javascript pour effectuer une mise au point.

Voici un exemple.

Dans le fichier html:

<input type="text" id="myInputId" />

Dans un fichier javascript, dans un contrôleur par exemple, où vous voulez activer le focus:

document.getElementById("myInputId").focus();

7
2018-06-20 14:56