2014-11-25 10 views
22

Aby uzyskać częściowy widok, chcę zrobić trochę kodu JavaScript, który zwykle robiłbym z $(document).ready(function() {...}), np. wiążą detektory weneckie z elementami. Wiem, że to nie działa dla AngularJS i częściowych widoków załadowanych do widoku "root".

W ten sposób dodałem słuchacza do kontrolera, który słucha zdarzenia $viewContentLoaded. Funkcja detektora jest wywoływana, więc zdarzenie jest uruchamiane, ale wydaje mi się, że jest to przed renderowaniem częściowym. Nie widzę również elementów, gdy ustawiam punkt przerwania w funkcji odbiornika i debuguję go przy użyciu firebug, ani też wybór jquery w funkcji nie odnajduje elementów częściowego widoku.

To co kontroler wygląda następująco:

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

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

[...] 

myślę, że robię coś złego, ponieważ nie musiało być więcej stanowisk na stackoverflow jeśli jest to wspólny błąd.

Ponieważ używam UI-routera i UI-view, dam wam fragment pliku routingu:

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

[...] 

Każda pomoc jest mile widziana. Dziękujemy i poważaniem

UPDATE 1: rozebrałem błąd w dół do następnego usecase: The loginView.html wygląda następująco:

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

[...] 

Jak tylko usunąć ng-if ze znacznika div działa zgodnie z oczekiwaniami. Zdarzenie jest wywoływane po renderowaniu modelu DOM, dlatego jQuery znajduje element. Jeśli ng-if jest dołączony do znacznika div, zachowanie jest po raz pierwszy opisane.

UPDATE 2: Zgodnie z obietnicą dodałem demo roboczy, który pokazuje różne zachowanie podczas dodawania dyrektywę ng-if. Czy ktoś może wskazać mi właściwy kierunek? Nie przyklejaj się do formularza logowania jako takiego, ponieważ istnieje wiele innych przypadków użycia, w których chcę usunąć określone części widoku w oparciu o pewne wyrażenie i zrobić pewne elementy JavaScript po przygotowaniu częściowego widoku.

można znaleźć demo pracuje tutaj: Demo

+0

Można utworzyć dyrektywy dla ciebie DOM rzeczy. – dfsq

+1

Stworzyłem [działające demo] (http://codepen.io/anon/pen/gbpmQy) na podstawie Twojego kodu i działa poprawnie. Następnym razem spróbuj dostarczyć wersję demonstracyjną. – hon2a

+0

Wielkie dzięki za działające demo. Zaktualizowałem opis, ponieważ odkryłem, że ng-if powoduje inne zachowanie. Czy masz pomysł, dlaczego zachowuje się inaczej? Wyrażenie jest oceniane jako "prawdziwe", ponieważ widzę formularz logowania, chwilę za późno;) – Florian

Odpowiedz

39

Jest to związane z kątowym strawić cyklu, to o tym, jak kanciasty prace pod maską, wiążące itd. Dane Istnieją wielkie samouczki wyjaśniające ten.

Aby rozwiązać problem, należy użyć $ limit czasu, będzie to uczynić kod wykonać w następnym cyklu, whem NG-jeśli był już analizowany: Fixed

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

demo tutaj: http://codepen.io/anon/pen/JoYPdv

Ale Radzę ci, abyś używał dyrektyw do jakiejkolwiek manipulacji DOM, kontroler nie jest do tego. Oto przykład tego, jak to zrobić: Easy dom manipulation in AngularJS - click a button, then set focus to an input element

+0

Uznam, że jest to najcenniejsza odpowiedź, ponieważ zapewnia możliwe rozwiązanie i wskazówkę, aby znaleźć dalsze informacje na temat cyklu trawienia, chociaż teraz używam dyrektywy. – Florian

+0

Bardzo dobrze wyjaśnione! Udało mi się zintegrować App.js i AngularJS przy użyciu powyższego fragmentu kodu, a także zrozumieć skomplikowane szczegóły dotyczące limitu czasu. – Nirus

+6

Problem z tym podejściem polega na tym, że w ui-routerze pożary $ viewContentLoaded dla każdego widoku. Jeśli masz wiele widoków na jednej stronie, Twój kod byłby wykonywany wiele razy. Czy istnieje sposób na wykonanie go tylko raz, gdy załadowano WSZYSTKIE widoki? – Hades

0

Jest to odpowiedź na Hades nieco późno, ale może pomóc komuś innemu. Skonfigurowałem usługę, którą później będę mógł wywołać z kontrolera lub dyrektywy.

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

 
    }; 
 
});

W regulatorze lub dyrektywy obejmują viewContentLoaded i wywołać funkcję Dostać się z obietnicy. Nie zapomnij zmienić aplikacji na nazwę jakiejkolwiek aplikacji i dołącz plik usługi do załadowania.

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

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

1

Mam rozwiązać ten problem za pomocą dyrektyw. Dodaj jedną DYREKTYWĘ do elementu (jak <div my-dir></div>) i zrobić manipulacje do elementu w odpowiedniej dyrektywy w następujący sposób,

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

Próbowałem również państwowe wydarzenia dostawcy jak $stateChangeSuccess, $viewContentLoaded, ale nie mógł rozwiązać ten problem. Ponieważ po wypaleniu tych wydarzeń, renderowanie w DOM wymaga trochę czasu.

Tak, możemy wykonać to podejście, które daje doskonałe rezultaty i właściwy sposób realizować w Angular JS :)