AngularJS: $ viewContentLoaded triggersto prima della visualizzazione parziale

Per una vista parziale voglio fare qualcosa di JavaScript che di solito farei con $(document).ready(function() {...}) , ad es. Legare gli ascoltatori venet agli elementi. So che questo non funziona per AngularJS e le viste parziali caricate nella vista “root”.

Così ho aggiunto un listener al controller che ascolta l’evento $viewContentLoaded . La funzione del listener viene invocata, quindi l’evento viene generato ma mi sembra che sia prima che venga visualizzata la vista parziale. Né vedo gli elementi quando imposto un breakpoint nella funzione dell’ascoltatore e lo faccio il debug con firebug, né la selezione jquery all’interno della funzione trova gli elementi della vista parziale.

Ecco come appare il controller:

 angular.module('docinvoiceClientAngularjsApp') .controller('LoginController', function ($scope, $rootScope) { $scope.$on('$viewContentLoaded', function(event) { console.log("content loaded"); console.log($("#loginForm")); // breakpoint here }); [...] 

Immagino che sto facendo qualcosa di sbagliato in quanto ci dovrebbero essere più messaggi su StackOverflow se questo è un bug comune.

Poiché sto usando ui-router e ui-view , ti darò un estratto del file di routing:

 angular .module('docinvoiceClientAngularjsApp', [ 'ui.router', 'ngAnimate', 'ngCookies', 'ngResource', 'ngMessages', 'ngRoute', 'ngSanitize', 'ngTouch' ]) .config(function ($routeProvider, $stateProvider) { $stateProvider .state('login', { url: '/', templateUrl: 'components/login/loginView.html', controller: 'LoginController' }) .run(['$state', function ($state) { $state.transitionTo('login'); }]) [...] 

Qualsiasi aiuto è apprezzato. Grazie e cordiali saluti

AGGIORNAMENTO 1: Ho eliminato l’errore nel seguente caso: Il loginView.html ha il seguente aspetto:

 
[...]

Non appena rimuovo il ng-if dal tag div, funziona come previsto. L’evento viene triggersto dopo il rendering del DOM, quindi jQuery trova l’elemento. Se ng-if è collegato al tag div, il comportamento è come descritto in precedenza.

AGGIORNAMENTO 2: Come promesso, ho aggiunto una demo funzionante che mostra il diverso comportamento quando si aggiunge una direttiva ng-if . Qualcuno può indicarmi la giusta direzione? Non attenersi al modulo di accesso in quanto tale, poiché ci sono molti altri casi d’uso in cui voglio rimuovere alcune parti di una vista basate su alcune espressioni e fare alcuni elementi JavaScript dopo che la vista parziale è pronta.

Puoi trovare la demo di lavoro qui: Demo

Questo è legato al ciclo di digestione angular, riguarda il modo in cui l’angular funziona sotto il cappuccio, il binding dei dati ecc. Ci sono ottimi tutorial che lo spiegano.

Per risolvere il tuo problema, usa $ timeout, farà eseguire il codice al ciclo successivo, whe il ng-if è già stato analizzato:

 app.controller('LoginController', function ($scope, $timeout) { $scope.$on('$viewContentLoaded', function(event) { $timeout(function() { $scope.formData.value = document.getElementById("loginForm").id; },0); }); }); 

Risolta la demo qui: http://codepen.io/anon/pen/JoYPdv

Ma ti consiglio caldamente di usare le direttive per manipolare DOM, il controller non è per questo. Ecco un esempio di come eseguire questa operazione: manipolazione semplice di dom in AngularJS: fare clic su un pulsante, quindi impostare lo stato attivo su un elemento di input

Ho risolto questo problema con l’aiuto delle direttive. Aggiungi una direcitve al tuo elemento (come

) e fai manipolazioni all’elemento nella rispettiva direttiva come segue,

 app.directive('myDir', function () { return { restrict: 'A', link: function (scope, element) { // Do manipulations here with the help of element parameter } }; }); 

Ho anche provato eventi del provider di stato come $stateChangeSuccess , $viewContentLoaded ma non ho potuto risolvere il problema. Perché dopo che questi eventi sono stati licenziati, ci vuole del tempo per eseguire il rendering sul DOM.

Quindi, possiamo seguire questo approccio che dà risultati perfetti e il modo corretto di implementare in Angular JS 🙂

Questa è una risposta ad Ade un po ‘in ritardo, ma potrebbe aiutare qualcun altro. Ho configurato un servizio che in seguito potrò chiamare da un controller o da una direttiva.

 'use strict'; app.factory('viewContentLoaded', function($q, $rootScope, $timeout) { var viewContentLoaded = $q.defer(), foo = function() { $timeout(function() { viewContentLoaded.resolve(); // Get all entries }, 100);//Timeout }, checkViewContenLoadedListner = $rootScope.$on('$viewContentLoaded', foo);//Rootscope return { getLoaded: function() { return viewContentLoaded.promise; }, removeViewContenListner: function() { //Remove event listern on $viewContentLoaded no $off so call it will unsubscribe it //$rootScope.$off('$viewContentLoaded', foo);//Rootscope //Don't forget to unsubscribe later checkViewContenLoadedListner(); } }; });