Dom işlemeyi bitirdikten sonra bir yönergeyi nasıl çalıştırabilirim?


115

Görünürde basit olmayan (Angular JS belgelerini okuyarak) bir çözümüm var.

DOM'daki bir kabın yüksekliğini tanımlamak için diğer DOM öğelerinin yüksekliğini temel alan bazı hesaplamalar yapan bir Angular JS yönergesine sahibim.

Direktifin içinde buna benzer bir şey var:

return function(scope, element, attrs) {
    $('.main').height( $('.site-header').height() -  $('.site-footer').height() );
}

Buradaki sorun, yönerge çalıştığında, $('site-header')ihtiyacım olan jQuery sarmalanmış DOM öğesi yerine boş bir dizi döndürerek bulunamamasıdır.

Yalnızca DOM yüklendikten sonra çalışan yönergemde kullanabileceğim ve diğer DOM öğelerine normal jQuery seçici tarzı sorgular aracılığıyla erişebildiğim bir geri çağrı var mı?


1
Özel etkinlikleri kullanmak için. $ On () ve. $ Emit () kapsamını kullanabilirsiniz. Yine de bunun doğru / önerilen yaklaşım olup olmadığından emin değilim.
Tosh

Yanıtlar:


137

$ ['Site-başlığınızın') nasıl oluşturulduğuna bağlıdır.

$ Timeout'u 0 gecikme ile kullanmayı deneyebilirsiniz . Gibi bir şey:

return function(scope, element, attrs) {
    $timeout(function(){
        $('.main').height( $('.site-header').height() -  $('.site-footer').height() );
    });        
}

Nasıl çalıştığına dair açıklamalar: bir , iki .

$timeoutDirektifinize enjekte etmeyi unutmayın :

.directive('sticky', function($timeout)

5
Teşekkürler, $timeoutyönergeye geçmediğimi anlayana kadar bunu uzun süre çalıştırmaya çalıştım . Hamuru. Artık her şey çalışıyor, şerefe.
Jannis

5
Evet, şu $timeoutşekilde yönergeye geçmeniz gerekiyor :.directive('sticky', function($timeout) { return function (scope, element, attrs, controller) { $timeout(function(){ }); }); };
Vladimir Starkov

19
Bağlantılı açıklamalarınız, zaman aşımı hilesinin neden JavaScript'te çalıştığını, ancak AngularJS bağlamında olmadığını açıklar. Gönderen Resmi belgelerin : " [...] 4. $ evalAsync kuyruk akımı yığın çerçevesinin dışında gerçekleşmesi gereken zamanlama çalışması için kullanılır, ancak tarayıcının bakış önce kılmak. Bu genellikle setTimeout (0) ile yapılır , fakat setTimeout (0) yaklaşımı yavaşlıktan muzdariptir ve tarayıcı görünümü her olaydan sonra oluşturduğundan görünümün titremesine neden olabilir. [...] "(vurgu benim)
Alberto

12
Benzer bir sorunla karşı karşıyayım ve yönergemi çalıştırmadan önce DOM'un yüklenmesine izin vermek için yaklaşık 300 ms'ye ihtiyacım olduğunu fark ettim. Görünüşe göre rastgele sayılar eklemeyi gerçekten sevmiyorum. Eminim DOM yükleme hızları kullanıcıya bağlı olarak değişecektir. Peki, 300 ms'nin uygulamamı kullanan herkes için çalışacağından nasıl emin olabilirim?
2014

5
bu cevaptan pek memnun değil .. OP'nin sorusuna cevap veriyor gibi görünse de .. bu onların durumuna çok özel ve problemin daha genel şekliyle alakalı (yani bir dom yüklendikten sonra bir direktif çalıştırmak) açık değil + çok hilekar .. İçinde açısal hakkında hiçbir şey yok
abbood

44

İşte bunu nasıl yapıyorum:

app.directive('example', function() {

    return function(scope, element, attrs) {
        angular.element(document).ready(function() {
                //MANIPULATE THE DOM
        });
    };

});

1
element.ready(function(){
Açısal

1
@ timhc22 öğesi, yönergeyi tetikleyen DOMElement'a bir referanstır, öneriniz, sayfaların Belge nesnesine bir DOMElement başvurusu ile sonuçlanmayacaktır.
tobius

bu düzgün çalışmıyor. Bu yaklaşımla offsetWidth = 0 alıyorum
Alexey Sh.

37

Muhtemelen yazarın artık cevabıma ihtiyacı olmayacak. Yine de, bütünlük adına, diğer kullanıcıların onu faydalı bulabileceğini düşünüyorum. En iyi ve en basit çözüm, $(window).load()döndürülen işlevin gövdesi içinde kullanmaktır . (alternatif olarak kullanabilirsinizdocument.ready . Gerçekten tüm resimlere ihtiyacınız olup olmadığına bağlıdır).

kullanma $timeoutBenim düşünceme göre çok zayıf bir seçenektir ve bazı durumlarda başarısız olabilir.

İşte kullanacağım kodun tamamı:

.directive('directiveExample', function(){
   return {
       restrict: 'A',
       link: function($scope, $elem, attrs){

           $(window).load(function() {
               //...JS here...
           });
       }
   }
});

1
Neden "bazı durumlarda başarısız olabileceğini" açıklayabilir misiniz? Hangi vakaları kastediyorsun?
rryter

6
JQuery'nin burada mevcut olduğunu varsayıyorsunuz.
Jonathan Cremin

3
@JonathanCremin jQuery seçme, OP uyarınca eldeki sorun
Nick Devereaux

1
Bu harika çalışıyor ancak direktifle yeni öğeler oluşturan bir gönderi varsa, pencere yükü ilk yüklemeden sonra ateşlenmeyecek ve bu nedenle düzgün çalışmayacaktır.
Brian Scott

@BrianScott - İlk sayfa oluşturma için $ (window) .load kombinasyonunu kullandım (kullanım durumum gömülü yazı tipi dosyalarını bekliyordu) ve ardından element.ready görünümleri değiştirmeye hazır.
aaaaaa

8

bir ngcontentloadedolay var bence kullanabilirsin

.directive('directiveExample', function(){
   return {
       restrict: 'A',
       link: function(scope, elem, attrs){

                $$window = $ $window


                init = function(){
                    contentHeight = elem.outerHeight()
                    //do the things
                }

                $$window.on('ngcontentloaded',init)

       }
   }
});

21
Ne yaptığını açıklayabilir misin $ $window?
Catfish

2
bir kahve kağıdına benziyor, belki de $ ($ window) ve $
window'un

5

Dış kaynaklar nedeniyle $ timeout kullanamıyorsanız ve belirli bir zamanlama sorunu nedeniyle bir yönergeyi kullanamıyorsanız, yayını kullanın.

$scope.$broadcast("variable_name_here");İstenilen harici kaynak veya uzun süre çalışan denetleyici / yönerge tamamlandıktan sonra ekleyin .

Harici kaynağınız yüklendikten sonra aşağıdakileri ekleyin.

$scope.$on("variable_name_here", function(){ 
   // DOM manipulation here
   jQuery('selector').height(); 
}

Örneğin, ertelenmiş bir HTTP isteği vaadinde.

MyHttpService.then(function(data){
   $scope.MyHttpReturnedImage = data.image;
   $scope.$broadcast("imageLoaded");
});

$scope.$on("imageLoaded", function(){ 
   jQuery('img').height(80).width(80); 
}

2
Bu, sorunu çözmeyecektir, çünkü yüklenen veriler, DOM öğelerine bağlı uygun kapsam değişkenlerinde olsalar bile, DOM'da zaten oluşturulmuş oldukları anlamına gelmez. Kapsama yüklendikleri an ile dom'da işlenen çıktı arasında bir zaman aralığı vardır.
René Stalder

1

Benzer bir sorun yaşadım ve çözümümü burada paylaşmak istiyorum.

Aşağıdaki HTML'ye sahibim:

<div data-my-directive>
  <div id='sub' ng-include='includedFile.htm'></div>
</div>

Sorun: Üst div yönergesinin bağlantı işlevinde, alt div # alt öğesini jquery'lemek istedim. Ama bana boş bir nesne verdi çünkü yönergenin link fonksiyonu çalıştırıldığında ng-include bitmemişti. Bu yüzden önce $ timeout ile kirli bir çözüm yaptım, bu işe yaradı, ancak gecikme parametresi istemci hızına bağlıydı (kimse bunu sevmez).

Çalışıyor ama kirli:

app.directive('myDirective', [function () {
    var directive = {};
    directive.link = function (scope, element, attrs) {
        $timeout(function() {
            //very dirty cause of client-depending varying delay time 
            $('#sub').css(/*whatever*/);
        }, 350);
    };
    return directive;
}]);

İşte temiz çözüm:

app.directive('myDirective', [function () {
    var directive = {};
    directive.link = function (scope, element, attrs) {
        scope.$on('$includeContentLoaded', function() {
            //just happens in the moment when ng-included finished
            $('#sub').css(/*whatever*/);
        };
    };
    return directive;
}]);

Belki birine yardımcı olur.

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.