2012-08-14 16 views
28

Come è possibile eseguire un metodo $scope.myWork() dopo il modello di rendering? Voglio impostare il $scope.value e dopo ho bisogno di cambiare qualcosa con JQuery (ad esempio nel DOM del contenuto del modello). $scope.$watch('value', function(){....}) funziona con il rendering "prima" (il DOM del modello non è ancora disponibile). Grazie.AngularJS: callback dopo il rendering (funziona con DOM dopo il rendering)

risposta

20

Creare un directive che esegue il codice nella funzione di collegamento. La funzione di collegamento viene chiamata dopo che il modello è stato creato.

Vedere ng-click per avere un'idea.

+0

C'è il mio esempio, che non funziona - http://jsfiddle.net/C6SUv/7/ (perché isn' t $ scope.afterRender call dopo ogni rendering?). – user1595465

+0

perché la funzione di collegamento viene chiamata una volta dopo il rendering dell'elemento, non dopo ogni rendering di angolare. Perché non è possibile creare direttive apportare le modifiche necessarie con jQuery e aggiornare angolare? Manipolare DOM all'interno dei controller non è una buona pratica –

+0

Hmmmmm. Devo scorrere div con altezza fissa. Ho i pulsanti per spostare il cursore nell'elenco dei campi. Ho impostato $ scope.value in ngClick e dopo di che ho bisogno di scorrere sulla posizione giusta (tramite scrollTop). Questa è la ragione, perché voglio manipolare DOM all'interno del controller. Qualche idea? – user1595465

15

Io uso terminal e transclude in una direttiva attributo per chiamare un metodo ambito dopo un modello viene aggiornato e la vista è resa (nel mio caso per ridimensionare un iframe dopo un $ Resource.query):

.directive('postRender', [ '$timeout', function($timeout) { 
var def = { 
    restrict : 'A', 
    terminal : true, 
    transclude : true, 
    link : function(scope, element, attrs) { 
     $timeout(scope.resize, 0); //Calling a scoped method 
    } 
}; 
return def; 
}]) 

Il timeout $ è magia nera. È dovrebbe essere possibile dichiarare il metodo JS come valore di attributo e $ analizzarlo.

per cui uso in un ng-repeat (nel mio caso un albero è reso in modo ricorsivo):

<div post-render ng-repeat="r in regions | orderBy:'name'" ng-include="'tree_region_renderer.html'"> 
2

Jens risposta di cui sopra funziona, ma si noti che sulle versioni più recenti AngularJS (ad esempio 1.2.3) si non può avere la direttiva postRender in combinazione con ng-repeat come attributi sullo stesso tag poiché entrambi hanno una transclude: true. In tal caso, è necessario rimuovere transclude o disporre di un tag separato con l'attributo direttiva postRender.
Inoltre, si tenga presente la priorità degli attributi quando si utilizza il terminale: true poiché si potrebbe finire per avere un attributo non efficace a causa di uno più priorotizzato sullo stesso tag.

7

Ho anche avuto questo problema, altre soluzioni non hanno funzionato bene per me, e mi è sembrato il tipo di cosa che il goniometro deve aver risolto. Una rapida revisione di Protractor's client-side scripts mostra che utilizza angular.getTestability(element) per sapere quando effettivamente eseguire i test. Il metodo attende finché non ci sono timeout in sospeso o richieste HTTP e quindi esegue la richiamata. Ecco la mia direttiva:

export function afterRender ($timeout) { 
"ngInject"; 
    return { 
     restrict: 'A', 
     terminal: true, 
     link: function (scope, element, attrs) { 
     angular.getTestability(element).whenStable(function() { 
      console.log('[rendered]'); 
     }); 
     } 
    }; 
} 
+1

Poiché si sta eseguendo all'interno dell'app Angular, si può semplicemente iniettare '$ browser' e registrare un callback con il suo metodo' notifyWhenNoOutstandingRequests() '. Si noti, tuttavia, che ciò si basa su alcune API private non documentate e potrebbe interrompersi senza preavviso. – gkalpak

-2

Ho trovato questa pagina quando cercavo un modo per profilare il rendering DOM. Ho trovato una soluzione molto semplice che funziona per il mio caso d'uso.

Collegare un gestore di ng-init all'elemento DOM e nella funzione di gestore, utilizzare $ timeout per ottenere l'esecuzione. Esempio:

HTML:

<div ng-init="foo()"> 

JS:

$scope.foo = function() { 
    $timeout(function() { 
     // This code runs after the DOM renders 
    }); 
}); 
Problemi correlati