2015-01-24 25 views
12

Immaginate alcuni contenuti pesanti che potrebbero essere visualizzati in una pagina Web, ad esempio un grafico. Angolare offre 2 opzioni per attivare la visibilità di tale contenuto.Combinazione angolare ng-if e ng-show

ng-show renderà il contenuto indipendentemente dall'espressione e semplice "nasconderlo" dopo il fatto. Questo non è l'ideale dato che l'utente non può mai "aprire" il contenuto durante la sua sessione, quindi è stato uno spreco renderlo.

ng-se è migliore in questo senso. Usarlo al posto di ng-show impedirà il rendering del contenuto pesante in primo luogo se l'espressione è falsa. Tuttavia, il suo punto di forza è anche la sua debolezza, perché se l'utente nasconde il grafico e lo mostra di nuovo, il contenuto viene visualizzato da zero ogni volta.

Come posso fare una direttiva che prende il meglio di entrambi i mondi? Significa che funziona come ng-if fino a quando il contenuto non viene reso per la prima volta, quindi passa a funzionare come ng-show per impedirne il re-rendering ogni volta.

+1

ng-lazy-show: http://developers.lendio.com/ blog/combining-ng-if-and-ng-show-per-meglio-angularjs-performance/ – rinogo

+0

Grazie, è esattamente quello che alla fine ho finito usando al momento – parliament

risposta

18

+1 sulla risposta di Denis, ma solo per completezza-sake, può anche essere ulteriormente semplificata, mantenendo la logica della vista senza "inquinare" il controllore:

<button ng-click="show = !show">toggle</button> 
<div ng-if="once = once || show" ng-show="show">Heavy content</div> 

plunker

EDIT: la versione di cui sopra potrebbe essere ulteriormente migliorata (e semplificata) con l'associazione una tantum per ridurre un inutile $ watch su once - questo funzionerà solo in Angular 1.3+:

<div ng-if="::show || undefined" ng-show="show">Heavy content</div> 

Il numero undefined è necessario per garantire che il valore visto non sia "stabilize" prima che diventi true. Una volta stabilizzato, perde anche l'orologio $, quindi non subirebbe alcun impatto con ulteriori modifiche a show.

+0

cool update, grazie! – parliament

+0

Suggerimento eccezionale, penserò a come riutilizzarlo, in qualche modo! – fjcero

+0

Grande trucco! Ma esiste un modo per ridisegnare le direttive quando necessario? – kashesandr

9

È possibile farlo funzionare utilizzando ngIf e ngShow insieme, in cui ognuno è controller per variabile diversa. ngIf sarà impostato su true una volta e non sarà mai impostato su false di nuovo, mentre ngShow verrà attivato quanto l'utente desidera.

Dai un'occhiata a questo fiddle.

+0

hmmm touché sir – parliament

5

E 'stata la risposta di @ new-dev che ha ispirato la mia idea di combinazione per ottenere velocemente un componente piuttosto pesante utilizzando un pulsante di attivazione/disattivazione.

Il mio problema originale era che la mia pagina è composta da ~ 20 componenti, ognuno dei quali richiede circa 1 secondo per caricarsi. Ogni essere attivato da un pulsante.

Se si utilizza semplicemente ng-se ottengo il caricamento immediato della pagina e 1 secondo dopo una pressione.

Se si utilizza pianura ng-spettacolo che avrei avuto le presse a ginocchiera istantanei mentre 20 secondi di ritardo di caricamento della pagina ...

Così, ora li combinano con un controllo ng-MouseEnter troppo. Come questo.

<div ng-mouseenter="create=true"> 
    <button ng-click="showAll = !showAll"></button> 
    <!--lightweight content--> 
    <div ng-show="showAll"> 
     <div ng-if="create"> 
      <!--Heavy content--> 
     </div> 
    </div> 
</div> 

Questo mi ha dato prestazioni eccellenti sia in cromo che in IE.Il tempo impiegato dall'utente per fare effettivamente clic sul pulsante dopo aver inserito il componente viene utilizzato per la creazione del DOM. E poi i nodi DOM vengono visualizzati rapidamente una volta (se) arriva il clic.

Non ho mai impostato nuovamente l'espressione ng-if su false. Mantenere il DOM memorizzato nella cache se l'utente continua ad attivare quella sezione.

Aggiornamento: Il motivo per cui non ho il ng-se e ng-spettacolo sulla stessa div è che in IE ha causato lo sfarfallio. Quando è arrivato l'evento mouseenter, mostra il contenuto e poi lo nasconde. In chrome era ok averlo sullo stesso div.

+0

Ciao, questo è ottimo per il mio caso. Non posso usare ng-mouseenter sul telefono però o posso? Qual è l'alternativa. –

+0

Hai ragione, Sul telefono o tablet non genera alcuna prestazione di velocità. Non so cosa usare poi. – tkarls

0

Potrebbe interessarti una direttiva personalizzata ng-lazy-show di Alan Colver. Permette che combina ng-if e ng-show:

<div ng-lazy-show="showFilters" lendio-business-filters></div> 

Il codice è piccolo e può essere facilmente aggiunto al progetto:

var ngLazyShowDirective = ['$animate', function ($animate) { 

    return { 
    multiElement: true, 
    transclude: 'element', 
    priority: 600, 
    terminal: true, 
    restrict: 'A', 
    link: function ($scope, $element, $attr, $ctrl, $transclude) { 
     var loaded; 
     $scope.$watch($attr.ngLazyShow, function ngLazyShowWatchAction(value) { 
     if (loaded) { 
      $animate[value ? 'removeClass' : 'addClass']($element, 'ng-hide'); 
     } 
     else if (value) { 
      loaded = true; 
      $transclude(function (clone) { 
      clone[clone.length++] = document.createComment(' end ngLazyShow: ' + $attr.ngLazyShow + ' '); 
      $animate.enter(clone, $element.parent(), $element); 
      $element = clone; 
      }); 
     } 
     }); 
    } 
    }; 

}]; 

angular.module('yourModule').directive('ngLazyShow', ngLazyShowDirective); 
Problemi correlati