angulaire ng-if ou ng-show répond lentement (délai de 2 secondes?)

87

J'essaie d'afficher ou de masquer un indicateur de chargement sur un bouton lorsqu'une demande est occupée. Je fais cela avec angular en modifiant la variable $ scope.loading lorsqu'une requête est en cours de chargement ou lorsqu'elle est terminée.

 $scope.login = function(){
     $scope.loading = true;
    apiFactory.getToken()
        .success(function(data){

        })
        .error(function(error){

        })
         .finally(function(){
               $timeout(function() {
                 $scope.loading = false;
               }, 0);
         });
 };

Dans le frontend:

<button ng-disabled="loading" class="button button-outline button-positive" type="submit">
Log in 
<span ng-if="loading" class="ion-refreshing"></span>
</button>

Cela fonctionne bien, mais l'icône de chargement (rafraîchissement des ions) est affichée pendant environ 2 secondes, tandis que la variable $ scope est mise à jour immédiatement. J'ai essayé $ scope. $ Apply mais cela ne semble pas être ce qui ne va pas ici, la portée est mise à jour très bien et immédiatement après la demande. C'est juste l'icône qui ne répond pas assez rapidement.

Merci de m'avoir aidé à comprendre cela!

Jorre
la source
2
Des animations impliquées?
tasseKATT
Négatif. Aucune animation impliquée. Utiliser ng-class à la place semble aider.
Jorre
J'ai le même problème ou un problème similaire. La portée est mise à jour immédiatement et correctement - j'ai vérifié cela en journalisant les messages des $scopefonctions ng-ifutilisées pour savoir si les éléments pertinents doivent être affichés. Cependant, les boutons avec ng-ifrestent mal visibles ou masqués pendant quelques secondes. Ensuite, après un court instant, tous les boutons prennent leur état visible / caché prévu. - J'ai contourné ce problème en utilisant à la ng-hideplace. Version angulaire 1.2.16.
KajMagnus
Une solution pour ceux qui n'utilisent aucune animation?
Zia Ul Rehman Mughal

Réponses:

124

Essayez de supprimer ngAnimate si vous ne l'utilisez pas à partir de la configuration de votre application et de la page index.html:

angular.module('myApp', [...'ngAnimate',...])

@Spock; si vous avez toujours besoin d'utiliser ngAnimate, laissez la configuration de votre application intacte et ajoutez simplement le CSS suivant:

.ng-hide.ng-hide-animate{
     display: none !important;
}

Cela masquera l'icône animée juste après que votre condition soit remplie.

Comme vous pouvez le voir, nous définissons .ng-hide-animate sur hidden. C'est ce qui provoque le retard pendant qu'il attend la fin de l'animation. Vous pouvez ajouter une animation à votre événement de masquage comme l'indique le nom de la classe au lieu de le masquer comme dans l'exemple ci-dessus.

Palvinder
la source
1
J'avais une page simple avec seulement deux ng-if, ng-showqui était visiblement lente. J'ai supprimé ngAnimateet cela a résolu le problème pour moi. Merci!
Eamonn Gahan le
1
Cela a résolu un problème que j'avais aussi ... Savez-vous pourquoi la présence de ngAnimate provoquait une transition lente?
Clark
Le même problème - la suppression de ngAnimate l'a résolu ... mais ce n'est pas bon ... de nombreux modules ont besoin de ngAnimate pour faire des animations sympas ... que faire? ngAnimattias où êtes-vous? :)
Spock
21
Dans le cas de ng-if, l'ajout juste .ng-leave { display:none; }à l'élément a fait l'affaire pour moi ( !importantn'était pas nécessaire).
Joao le
40

J'ai eu le même problème et je l'ai contourné en utilisant ng-class avec le nom de classe «hidden» pour masquer l'élément au lieu d'utiliser ng-if ou ng-show / ng-hide.

neimad
la source
1
Cela semble lié aux animations et / ou aux gestionnaires d'événements. Je ne sais pas vraiment pourquoi les autres sont lents, mais j'aimerais savoir
Thiago Festa
1
Comment peux-tu faire ça?
jsmedmar
C'est tellement plus rapide! Pourquoi est-ce??
Aron
1
Je pense que c'est simplement dû au fait que l'utilisation de ngAnimate applique des comportements d'animation d'entrée / sortie aux éléments utilisant ng-if / ng-show, alors que ce n'est pas le cas pour les changements dans les expressions ng-class.
John Rix
@neimad comment est-ce fait? Dans mon cas, je dois utiliser ng-if pour tester si une valeur de propriété est null(ce qu'elle est pendant quelques secondes en attendant l'appel de l'API), donc deux éléments de sélection s'affichent brièvement. Alors n'utilisez-vous pas ng-if du tout? Merci.
Chris22
15

J'ai trouvé quelques solutions ici , mais la meilleure pour moi était de remplacer le style de la classe .ng-animate:

.ng-animate.no-animate {
    transition: 0s none;
    -webkit-transition: 0s none;
    animation: 0s none;
    -webkit-animation: 0s none;
}

En html:

<button ng-disabled="loading" class="button button-outline button-positive" type="submit">
    Log in 
    <span ng-if="loading" class="ion-refreshing no-animate"></span>
</button>

Ceci est un exemple: http://jsfiddle.net/9krLr/27/

J'espère vous aider.

Ruben Perez
la source
10

J'étais confronté à un problème similaire, j'ai utilisé $scope.$evalAsync() de forcer la mise à jour de la liaison.

Il fonctionne comme un charme.

Évitez d'utiliser $scope.$applycar cela peut entrer en conflit avec une phase $ digest déjà en cours d'exécution.

if(selectedStatistics.length === 0 || selectedWorkgroups.length === 0){
    ctrl.isSaveDisabled = true;
    $scope.$evalAsync();
} else{
    ctrl.isSaveDisabled = false;
    $scope.$evalAsync();
}
rach8garg
la source
A travaillé pour moi. Mais a-t-il des inconvénients?
Sarah Tammam
1
Je n'en ai rencontré aucun. C'est très pratique en cas d'opérations asynchrones.
rach8garg
1
Merci pour la réponse utile :)
Sarah Tammam
Cette réponse semble être un jackpot, merci.
Abdeali Chandanwala
Au fait, ce problème retardé se produit principalement dans l'environnement localhost et rarement en production - je ne sais pas pourquoi
Abdeali Chandanwala
1

J'ai eu le même problème lors de l'utilisation

<div *ngIf='shouldShow'>
    <!-- Rest of DIV content here -->
</div>

Dans mon cas, je l'ai résolu en ajoutant une classe:

.hidden {
  display: none;
}

puis en ajoutant la classe conditionnellement au lieu d'utiliser *ngIf:

<div [ngClass]="{'hidden': !shouldShow}">
    <!-- Rest of DIV content here -->
</div>

Si vous l'utilisez toujours de cette façon, j'envisagerais shouldShowde renommer en shouldHide(et d'annuler la logique qui l'attribue), afin qu'il puisse être utilisé comme shouldHideau lieu de !shouldShow.

Si vous avez display: flexdans votre CSS pour la classe existante de DIV, cette propriété d'affichage peut avoir la priorité sur le display: hidden. Une solution simple peut être d'utiliser à la display: none !importantplace, mais il existe souvent de meilleures solutions pour garantir la priorité par d'autres moyens. Voici une bonne lecture sur les alternatives .

Kent Munthe Caspersen
la source
0

dans la version angulaire 1.5.x en ajoutant $scope.$apply()après le changement de condition fait le travail pour moi voici un exemple de fonction

$scope.addSample = function(PDF)
        {
            var validTypes ="application/pdf";
            if(PDF.type == validTypes)
            {
                //checking if the type is Pdf and only pdf
                $scope.samplePDF= PDF.files[0];
                $scope.validError = false;
                $scope.$apply();
            }

            else
            {
                 $scope.validError = true;
                 $scope.samplePDF= null;
                 $scope.$apply();
            }


        }
mohamed
la source