web-dev-qa-db-fra.com

Différer l'exécution de la montre angularjs après $ digest (déclencher un événement DOM)

J'ai une montre qui déclenche un événement DOM:

scope.$watch(function() { return controller.selected; }, function(selected) {
    if (selected) {
        $input.trigger('focus');
    }
});

Le problème est que j'ai un gestionnaire sur "focus" qui fait un scope.$apply.

$input.bind('focus', function() {
    scope.$apply(function() { controller.focused = true; });
});

Alors quand mon $watch est tiré depuis l'intérieur d'un $digest il provoque une erreur car il essaie d'en déclencher un autre $digest.

La solution de contournement que j'ai est de mettre le déclencheur dans un $timeout.

scope.$watch(function() { return controller.selected; }, function(selected) {
    if (selected) {
        $timeout(function() { $input.trigger('focus'); });
    }
});

Cela fonctionne ... jusqu'à présent. Est-ce la bonne façon de gérer cela? Je ne suis pas sûr que cela intercepte tous les cas et j'aimerais voir s'il existe une méthode angular approuvée pour faire reporter un morceau de code après le résumé).

Merci!

31
anonymous

$ timeout est normalement ce qui est utilisé pour exécuter quelque chose après un cycle de résumé (et après le rendu du navigateur).

$timeout provoquera l'exécution d'un autre cycle de résumé après l'exécution de la fonction. Si votre trigger n'affecte rien Angular, vous pouvez définir l'argument invokeApply sur false pour éviter d'exécuter un autre cycle de résumé.

Si vous souhaitez que votre rappel s'exécute avant le navigateur affiche: Si le code est mis en file d'attente à l'aide de $evalAsync à partir d'une directive, il devrait s'exécuter après que le DOM a été manipulé par Angular, mais avant le rendu du navigateur. Cependant, si le code est mis en file d'attente à l'aide de $evalAsync depuis un contrôleur, il s'exécutera avant que le DOM ait été manipulé par Angular (et avant le rendu du navigateur). Voir aussi https : //stackoverflow.com/a/17303759/215945 .

65
Mark Rajcok

Comme tout le monde ne cesse de le dire, vous ne devriez pas faire de choses DOM dans votre contrôleur.

Voici une solution qui applique la liaison de données bidirectionnelle au focus. Maintenant, votre focus est lié à une variable. Ainsi, lorsque vous définissez la variable sur true, elle définit le focus sur l'élément correspondant et lorsque l'élément obtient le focus, la variable est définie.

http://plnkr.co/edit/CvPCVxy4MfJEM1UksrrA?p=preview

Nous avons maintenant réussi à séparer le focus du code du contrôleur. Il prend également en charge tous les problèmes de dépassement de délai (je suppose). La seule chose dont vous devez être conscient est que vous ne devez pas utiliser la même variable pour vous lier au focus de deux éléments différents.

EDIT: Mise à jour du plunk car le précédent ne fonctionnait pas bien.

0
ganaraj