2014-11-25 5 views
22

Für eine Teilansicht möchte ich einige JavaScript-Sachen tun, die ich normalerweise mit $(document).ready(function() {...}), z. binden Sie die Hörer an Elemente. Ich weiß, dass dies nicht für AngularJS und Teilansichten funktioniert, die in die "root" -Ansicht geladen werden.

Also habe ich einen Listener zum Controller hinzugefügt, der auf das Ereignis $viewContentLoaded hört. Die Funktion des Listeners wird aufgerufen, so dass das Ereignis ausgelöst wird, aber es scheint mir so zu sein, als wäre es bevor die Teilansicht gerendert wird. Ich sehe die Elemente auch nicht, wenn ich einen Haltepunkt in der Funktion des Listeners setze und ihn mit Firebug debugge, noch findet die jQuery-Auswahl innerhalb der Funktion die Elemente der Teilansicht. Diese

ist, was die Steuerung wie folgt aussieht:

angular.module('docinvoiceClientAngularjsApp') 
    .controller('LoginController', function ($scope, $rootScope) { 

$scope.$on('$viewContentLoaded', function(event) { 
    console.log("content loaded"); 
    console.log($("#loginForm")); // breakpoint here 
}); 

[...] 

Ich denke, dass ich etwas tue, falsch, da es hatte mehr Beiträge auf Stackoverflow, wenn dies ein weit verbreiteter Fehler ist.

Wie ich ui-Router und ui-Ansicht, verwende werde ich Ihnen einen Auszug aus der Routing-Datei geben:

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'); 
    }]) 

[...] 

Jede Hilfe sehr geschätzt wird. Dank und freundlichen Grüßen

UPDATE 1: ich den Fehler bis auf die folgenden usecase gestrippt: Die loginView.html sieht wie folgt aus:

<div id="loginContainer" style="width: 300px"> 
    <form id="loginForm" ng-submit="login(credentials)" ng-if="session.token == undefined"> 

[...] 

Sobald ich die ng-if aus dem div-Tag entfernen Es funktioniert wie erwartet. Das Ereignis wird ausgelöst, nachdem das DOM gerendert wurde. Daher findet jQuery das Element. Wenn die ng-if an das Div-Tag angefügt ist, ist das Verhalten wie zuerst beschrieben.

UPDATE 2: Wie versprochen habe ich eine funktionierende Demo hinzugefügt, die das unterschiedliche Verhalten beim Hinzufügen einer ng-if Direktive zeigt. Kann mir jemand die richtige Richtung zeigen? Halten Sie sich nicht an das Login-Formular, da es viel mehr Anwendungsfälle gibt, in denen ich bestimmte Teile einer Ansicht basierend auf einem Ausdruck entfernen und ein paar JavaScript-Sachen machen möchte, nachdem die Teilansicht fertig ist.

können Sie die Arbeits Demo finden Sie hier: Demo

+0

Sie eine Richtlinie für Sie DOM Sachen erstellen können. – dfsq

+1

Ich habe eine [Arbeitsdemo] (http://codepen.io/anon/pen/gbpmQy) basierend auf Ihrem Code erstellt und es funktioniert ordnungsgemäß. Beim nächsten Mal versuch bitte, die Demo selbst zu erstellen. – hon2a

+0

Vielen Dank für die funktionierende Demo. Ich habe die Beschreibung aktualisiert, als ich herausgefunden habe, dass das ng-if das unterschiedliche Verhalten verursacht. Hast du eine Idee, warum es sich anders verhält? Der Ausdruck wird zu "wahr" bewertet, da ich das Login-Formular sehen kann, nur einen Moment zu spät;) – Florian

Antwort

39

Dies zu Winkel verdauen Zyklus verwandt ist, es geht darum, wie Winkel arbeitet unter der Haube, Datenbindung etc. Es gibt große Tutorials dies zu erklären.

Um Ihr Problem, Verwendung $ timeout zu lösen, wird es der Code auf den nächsten Zyklus auszuführen machen, whem die ng-wenn bereits analysiert wurde:

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

Demo hier Fixed: http://codepen.io/anon/pen/JoYPdv

Aber Ich rate Dir dringend, Direktiven zu verwenden, die irgendeine DOM-Manipulation machen, der Controller ist dafür nicht geeignet. Hier ist ein Beispiel dafür, wie dies zu tun: Easy dom manipulation in AngularJS - click a button, then set focus to an input element

+0

Ich werde dies als die wertvollste Antwort betrachten, da es eine mögliche Lösung und einen Hinweis bietet, weitere Informationen über den Digest-Zyklus zu finden, obwohl ich jetzt eine Direktive verwende. – Florian

+0

Sehr gut erklärt! Ich war in der Lage, App.js und AngularJS zu integrieren, indem ich den obigen Code-Chunk verwendete und auch komplizierte Details der Zeitüberschreitung verstand. – Nirus

+6

Das Problem mit diesem Ansatz ist, dass in ui-Router $ viewContentLoaded für jede einzelne Ansicht ausgelöst wird. Wenn Sie viele Ansichten auf einer Seite haben, wird Ihr Code mehrmals ausgeführt. Gibt es eine Möglichkeit, es nur einmal ausführen zu lassen, wenn ALLE Ansichten geladen sind? – Hades

0

Dies ist eine Antwort auf Hades ein bisschen spät, aber vielleicht jemand anderes helfen. Ich habe einen Dienst eingerichtet, den ich später von einem Controller oder einer Direktive aufrufen kann.

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

 
    }; 
 
});

In der Steuerung oder Richtlinie umfasst viewContentLoaded und die get-Funktion mit dem Versprechen nennen. Vergiss nicht, die App in den Namen deiner App zu ändern und die zu ladende Servicedatei einzuschließen.

viewContentLoaded.getLoaded().then(function(){ 
 
    //Remove Listner when done 
 
    viewContentLoaded.removeViewContenListner(); 
 
    //Your code to run  
 

 
}, function(reason) { 
 
    //$log.error(reason); 
 
});

1

Ich habe dieses Problem mit Hilfe von Richtlinien gelöst. Fügen Sie ein direcitve zu Ihrem Element (wie <div my-dir></div>) und tun Manipulationen an das Element in jeweiligen Richtlinie wie folgt

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

Ich habe auch staatliche Anbieter Ereignisse versucht, wie $stateChangeSuccess, $viewContentLoaded konnte aber das Problem nicht lösen. Nachdem diese Ereignisse ausgelöst wurden, dauert es einige Zeit, bis das DOM gerendert ist.

So können wir diesen Ansatz verfolgen, die perfekte Ergebnisse und richtige Art und Weise gibt in Angular JS zu implementieren :)

Verwandte Themen