Belge hazırda AngularJS kontrol cihazında fonksiyon nasıl çalıştırılır?


254

Açısal denetleyicim içinde bir işlevim var, bu işlevin belgeye hazır olarak çalıştırılmasını istiyorum, ancak dom oluşturulurken açısal çalıştığını fark ettim.

 function myController($scope)
 {
     $scope.init = function()
     {
        // I'd like to run this on document ready
     }

     $scope.init(); // doesn't work, loads my init before the page has completely loaded
 }

Bunu nasıl yapabileceğimi bilen var mı?

Yanıtlar:


449

Biz kullanabilirsiniz angular.element(document).ready()belge hazır olduğunda geri aramalar takmak için yöntem. Geri aramayı denetleyiciye şu şekilde ekleyebiliriz:

angular.module('MyApp', [])

.controller('MyCtrl', [function() {
    angular.element(document).ready(function () {
        document.getElementById('msg').innerHTML = 'Hello';
    });
}]);

http://jsfiddle.net/jgentes/stwyvq38/1/


64
veya $ document.ready (function () {...}), Açısal Dokümanlar'ı kullanabilirsiniz: docs.angularjs.org/api/ng/service/$document
StuR

29
Kullanmak için enjekte $documentetmeniz gerekir. angular.elementkutudan çıkar çıkmaz çalışır.
nshew

17
Kullanmak için $ document enjekte etmeniz gerekir, ancak belge öğesine başvurmak için önerilen yöntem budur. Bunu yapmak zorunda değilsiniz, ancak testi kolaylaştırır.
Jason Cox

10
documentküresel bir değişkendir ve burada $documentaçısal ile enjekte edilebilir ve böylece testi kolaylaştırır. Genel olarak, belge veya pencere gibi global JS değişkenlerine erişen birim test uygulamalarını zor test eder. Ayrıca module.rundenetleyici yerine bu kodu koymak için iyi bir yer olduğunu düşünüyorum .
lanoxx

7
Bu benim için çalışmıyor, getElementById çağrısı null döndürür.
ThePartyTurtle

29

Bu gönderiye bakınız Sayfa yüklemesinde açısal denetleyici işlevi nasıl yürütülür?
Hızlı arama için:

// register controller in html
<div data-ng-controller="myCtrl" data-ng-init="init()"></div>

// in controller
$scope.init = function () {
    // check if there is query in url
    // and fire search in case its value is not empty
};

Bu şekilde, belge hazır olana kadar beklemek zorunda kalmazsınız.


1
sayfa yüklendikten sonra aramam gerekirse ne olur?
Rishi

22

Angular, DOMContentLoadedolay üzerine veya angular.js komut dosyası o anda document.readyState 'tamamlandı' olarak ayarlanmışsa değerlendirildiğinde otomatik olarak başlatılır . Bu noktada Angular, uygulama kökünüzü belirleyen ng-uygulama yönergesini arar.

https://docs.angularjs.org/guide/bootstrap

Bu, DOM hazır olduktan sonra denetleyici kodunun çalışacağı anlamına gelir.

Böylece sadece $scope.init().


9
Bunu yapmaya çalıştım ama garip bir şekilde sayfamdaki bazı şeyler işe yaramadı
foreyez

ve aotomlu web testleri yazarken düğmeler vb. gibi eylemleri gerçekleştirmeden önce açısal kodun ne zaman hazır olduğunu nasıl bilebilirsiniz?
akostadinov

Ayrıca DOMContentLoaded, stil sayfaları, resimler ve alt çerçevelerin yüklenmesini bitirmesini beklemeden belge tamamen yüklendiğinde ve ayrıştırıldığında da tetiklenir. Daha fazla bilgi için bkz. DOMContentLoaded ve load olayları arasındaki fark nedir? .
georgeawg

22

Açısal, işlevleri yürütmeye başlamak için birkaç zaman noktasına sahiptir. Eğer jQuery's gibi bir şey arıyorsanız

$(document).ready();

Bu analogu açısal olarak çok yararlı bulabilirsiniz:

$scope.$watch('$viewContentLoaded', function(){
    //do something
});

DOM öğelerini değiştirmek istediğinizde bu yardımcı olur. Yalnızca tüm elemanlar yüklendikten sonra yürütmeye başlayacaktır.

UPD: Yukarıda söylenenler css özelliklerini değiştirmek istediğinizde çalışır. Ancak, bazen genişlik, yükseklik vb. Gibi öğe özelliklerini ölçmek istediğinizde çalışmaz. Bu durumda bunu denemek isteyebilirsiniz:

$scope.$watch('$viewContentLoaded', 
    function() { 
        $timeout(function() {
            //do something
        },0);    
});

Bu, önerilen cevaptan daha fazlasını hak ediyor. Bu işi $ timeout kullanmadan aldım.
Richie86

benim için sadece setTimeout (0) ile çalışıyor - örneğin bir ng-repeat içeriği olmadan bu noktada henüz yüklenmiyor
Ignacio Vazquez

2

Görünüm yüklendikten sonra ve ayrıca görünüm içindeki belirli bir 3. taraf bileşen yüklendikten, başlatıldıktan ve $ kapsamına bir başvuru yerleştirdikten sonra bir denetleyici işlevini yürütmem gerektiğinde de benzer bir durum yaşadım. Benim için işe yarayan şey, bu scope özelliğine bir saat kurmak ve işlevimi ancak başlatıldıktan sonra ateşlemekti.

// $scope.myGrid property will be created by the grid itself
// The grid will have a loadedRows property once initialized

$scope.$watch('myGrid', function(newValue, oldValue) {
    if (newValue && newValue.loadedRows && !oldValue) {
        initializeAllTheGridThings();
    }
});

Gözcü, tanımlanmamış değerlerle birkaç kez çağrılır. Daha sonra ızgara oluşturulduğunda ve beklenen özelliğe sahip olduğunda, başlatma işlevi güvenli bir şekilde çağrılabilir. İzleyici tanımsız yeni bir değerle ilk kez çağrıldığında, eski Değer hala tanımsız olacaktır.


1

İşte coffeescript kullanarak bir dış denetleyicinin içindeki girişimim. Oldukça iyi çalışıyor. Ayarlar.screen.xs | sm | md | lg uygulamasına eklediğim, çoğaltılmamış bir dosyada tanımlanan statik değerler olduğunu lütfen unutmayın. Değerler, adsız ortam sorgu boyutları için Bootstrap 3 resmi sınır değerlerine uygundur:

xs = settings.screen.xs // 480
sm = settings.screen.sm // 768
md = settings.screen.md // 992
lg = settings.screen.lg // 1200

doMediaQuery = () ->

    w = angular.element($window).width()

    $scope.xs = w < sm
    $scope.sm = w >= sm and w < md
    $scope.md = w >= md and w < lg
    $scope.lg = w >= lg
    $scope.media =  if $scope.xs 
                        "xs" 
                    else if $scope.sm
                        "sm"
                    else if $scope.md 
                        "md"
                    else 
                        "lg"

$document.ready () -> doMediaQuery()
angular.element($window).bind 'resize', () -> doMediaQuery()

1

Cevap

$scope.$watch('$viewContentLoaded', 
    function() { 
        $timeout(function() {
            //do something
        },0);    
});

test ettiğim çoğu senaryoda çalışan tek model. Tümü bir şablondan HTML oluşturan 4 bileşenli bir örnek sayfada, etkinliklerin sırası

$document ready
$onInit
$postLink
(and these 3 were repeated 3 more times in the same order for the other 3 components)
$viewContentLoaded (repeated 3 more times)
$timeout execution (repeated 3 more times)

Bu yüzden açısal olarak inşa edilen DOM hiçbir yerde hazır olmayabilir, çünkü bir $ document.ready () çoğu durumda işe yaramaz.

Ancak daha ilginç, $ viewContentLoaded tetiklendikten sonra bile, ilgi alanı hala bulunamadı.

Yalnızca $ timeout çalıştırıldıktan sonra bulundu. $ Zaman aşımı değeri 0 olsa da, çalıştırılmadan önce yaklaşık 200 milisaniyenin geçtiğini ve bu iş parçacığının, muhtemelen DOM'un ana iş parçacığına açısal şablonlar eklerken bir süre kapalı tutulduğunu gösterdiğini unutmayın. İlk $ document.ready () ile son $ timeout yürütme arasındaki toplam süre yaklaşık 500 milisaniyeydi.

Bir bileşenin değerinin ayarlandığı ve daha sonra $ zaman aşımına göre text () değerinin değiştirildiği olağanüstü bir durumda, $ zaman aşımı değerinin çalışana kadar artırılması gerekiyordu (öğe $ zaman aşımı sırasında bulunabilse bile) ). 3. taraf bileşenindeki zaman uyumsuz bir şey, değerin, yeterli zaman geçene kadar metin üzerinde önceliğe sahip olmasına neden oldu. Başka bir olasılık ise $ scope. $ EvalAsync, ancak denenmedi.

Hala DOM'un tamamen yerleştiğini ve tüm vakaların çalışması için manipüle edilebileceğini söyleyen bir olayı arıyorum. Şimdiye kadar keyfi bir zaman aşımı değeri gereklidir, yani en iyi ihtimalle bu yavaş bir tarayıcıda çalışmayabilecek bir çamurdur. LiveQuery ve yayınlamak / çalışmak, ama kesinlikle saf açısal değildir abone olmak gibi JQuery seçenekleri denemedim.


1

Gibi bir şey alıyorsanız getElementById call returns null, büyük olasılıkla işlevin çalışması nedeniyle, ancak kimliğin DOM'a yüklenmek için zamanı yoktu.

Will'in cevabını (yukarı doğru) gecikmeli olarak kullanmayı deneyin. Misal:

angular.module('MyApp', [])

.controller('MyCtrl', [function() {
    $scope.sleep = (time) => {
        return new Promise((resolve) => setTimeout(resolve, time));
    };
    angular.element(document).ready(function () {
        $scope.sleep(500).then(() => {        
            //code to run here after the delay
        });
    });
}]);

0

Neden açısal dokümanların bahsettiklerini https://docs.angularjs.org/api/ng/function/angular.element ile denemiyorsunuz .

angular.element (geri)

Bunu $ onInit () {...} fonksiyonum içinde kullandım.

 var self = this;

 angular.element(function () {
        var target = document.getElementsByClassName('unitSortingModule');
        target[0].addEventListener("touchstart", self.touchHandler, false);
        ...
    });

Bu benim için çalıştı.


Sitemizi kullandığınızda şunları okuyup anladığınızı kabul etmiş olursunuz: Çerez Politikası ve Gizlilik Politikası.
Licensed under cc by-sa 3.0 with attribution required.