angular ng-if o ng-show risponde lentamente (2 secondi di ritardo?)


87

Sto cercando di mostrare o nascondere un indicatore di caricamento su un pulsante quando una richiesta è occupata. Lo faccio con angular modificando la variabile $ scope.loading quando una richiesta viene caricata o quando ha terminato il caricamento.

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

        })
        .error(function(error){

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

Nel frontend:

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

Funziona bene, ma l'icona di caricamento (ion-refreshing) viene visualizzata per circa 2 secondi, mentre la variabile $ scope viene aggiornata immediatamente. Ho provato $ scope. $ Apply ma non sembra essere ciò che non va qui, l'ambito viene aggiornato correttamente e immediatamente dopo la richiesta. È solo l'icona che non risponde abbastanza rapidamente.

Grazie per avermi aiutato a capire questo!


2
Eventuali animazioni coinvolte?
tasseKATT

Negativo. Nessuna animazione coinvolta. L'uso di ng-class sembra invece aiutare.
Jorre

Ho lo stesso problema o un problema simile. L'ambito viene aggiornato immediatamente e correttamente: l'ho verificato registrando i messaggi dall'interno delle $scopefunzioni che ng-ifutilizza per scoprire se gli elementi rilevanti devono essere visualizzati. Tuttavia, i pulsanti ng-ifrimangono visibili o nascosti in modo errato per alcuni secondi. Quindi, dopo un po 'di tempo, tutti i pulsanti assumono lo stato visibile / nascosto previsto. - Ho aggirato questo problema usando ng-hideinvece. Versione angolare 1.2.16.
KajMagnus

Qualche soluzione per coloro che non utilizzano animazioni?
Zia Ul Rehman Mughal,

Risposte:


124

Prova a rimuovere ngAnimate se non lo stai utilizzando dalla configurazione dell'app e dalla pagina index.html:

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

@Spock; se hai ancora bisogno di usare ngAnimate, lascia la configurazione della tua app intatta e aggiungi semplicemente il seguente CSS:

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

Ciò nasconderà l'icona animata subito dopo che la tua condizione è soddisfatta.

Come puoi vedere, stiamo impostando .ng-hide-animate su nascosto. Questo è ciò che causa il ritardo mentre attende il completamento dell'animazione. Puoi aggiungere un'animazione al tuo evento hide come suggerisce il nome della classe invece di nasconderla come nell'esempio sopra.


1
Avevo una pagina semplice con solo un paio di ng-if, ng-showche era visibilmente lenta. Ho rimosso ngAnimatee ha risolto il problema per me. Grazie!
Eamonn Gahan

1
Questo ha risolto un problema che stavo avendo anche io ... Sai perché la presenza di ngAnimate stava causando la transizione lenta?
Clark

Aveva lo stesso problema: rimuovere ngAnimate lo ha risolto .. ma questo non va bene .. molti moduli hanno bisogno di ngAnimate per fare animazioni fantastiche .. cosa fare? ngAnimattias dove sei? :)
Spock

21
Nel caso di ng-if, l'aggiunta solo .ng-leave { display:none; }all'elemento ha fatto il trucco per me ( !importantnon era necessario).
Joao

40

Ho avuto lo stesso problema e ho risolto il problema utilizzando ng-class con il nome della classe "nascosto" per nascondere l'elemento invece di utilizzare ng-if o ng-show / ng-hide.


1
Sembra correlato alle animazioni e / o ai gestori di eventi. Non sono proprio sicuro del motivo per cui gli altri sono lenti, ma mi piacerebbe sapere
Thiago Festa

1
come puoi farlo?
jsmedmar

Questo è molto più veloce! Perchè è questo??
Aron

1
Penso che sia semplicemente dovuto al fatto che l'uso di ngAnimate applica i comportamenti di animazione di entrata / uscita agli elementi che usano ng-if / ng-show, mentre non lo fa per le modifiche nelle espressioni di ng-class.
John Rix

@neimad come si fa? Nel mio caso, devo usare ng-if per verificare se il valore di una proprietà è null(che è per un paio di secondi in attesa della chiamata api), quindi due elementi di selezione vengono visualizzati brevemente. Quindi non stai usando ng-if affatto? Grazie.
Chris22

15

Ho trovato alcune soluzioni qui , ma la cosa migliore per me è stata sovrascrivere lo stile per la classe .ng-animate:

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

In 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>

Questo è un esempio: http://jsfiddle.net/9krLr/27/

Spero di aiutarti.


10

Stavo affrontando un problema simile, ho usato $scope.$evalAsync()per forzare l'aggiornamento dell'associazione.

Esso funziona magicamente.

Evita di usarlo $scope.$applyin quanto può entrare in conflitto con una fase $ digest già in esecuzione.

if(selectedStatistics.length === 0 || selectedWorkgroups.length === 0){
    ctrl.isSaveDisabled = true;
    $scope.$evalAsync();
} else{
    ctrl.isSaveDisabled = false;
    $scope.$evalAsync();
}

Ha funzionato per me. Ma ha degli svantaggi?
Sarah Tammam

1
Non ne ho incontrati. È molto utile in caso di operazioni asincrone.
rach8garg

1
Grazie per l'utile risposta :)
Sarah Tammam

Questa risposta sembra essere un jackpot, grazie.
Abdeali Chandanwala

A proposito, questo problema in ritardo si verifica principalmente nell'ambiente localhost e raramente in produzione - non so perché
Abdeali Chandanwala

1

Ho avuto lo stesso problema durante l'utilizzo

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

Nel mio caso l'ho risolto aggiungendo una classe:

.hidden {
  display: none;
}

e quindi aggiungere la classe in modo condizionale invece di usare *ngIf:

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

Se lo si utilizza sempre in questo modo, prenderei in considerazione la possibilità di rinominare shouldShowin shouldHide(e negare la logica che lo assegna), in modo che possa essere utilizzato come shouldHideinvece di !shouldShow.

Se hai display: flexnel tuo CSS per la classe esistente del DIV, quella proprietà di visualizzazione potrebbe avere la precedenza su display: hidden. In display: none !importantalternativa, è possibile utilizzare una soluzione semplice , ma spesso esistono soluzioni migliori per garantire la precedenza in altri modi. Ecco una buona lettura delle alternative .


0

nella versione angolare 1.5.x l'aggiunta $scope.$apply()dopo la modifica della condizione ha fatto il lavoro per me ecco una funzione di esempio

$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();
            }


        }
Utilizzando il nostro sito, riconosci di aver letto e compreso le nostre Informativa sui cookie e Informativa sulla privacy.
Licensed under cc by-sa 3.0 with attribution required.