AngularJS yüklemeyi bitirdiğinde olay gönderme


114

Tüm yönergeler derleme / bağlama işlemini tamamladığında, sayfa yükleme / önyükleme işleminin bittiğini tespit etmenin en iyi yolunun ne olduğunu merak ettik.

Zaten orada herhangi bir olay var mı? Önyükleme işlevini aşırı yüklemeli miyim?

Yanıtlar:


204

Sadece bir önsezi: neden ngCloak yönergesinin bunu nasıl yaptığına bakmayalım? Açıkça ngCloak yönergesi, içerik yüklendikten sonra içeriği göstermeyi başarır. Bahse girerim ngCloak'a bakmak kesin cevaba götürecek ...

1 saat sonra DÜZENLE: Tamam, ngCloak'a baktım ve gerçekten kısa. Bunun açıkça ima ettiği şey, derleme işlevinin {{şablon}} ifadeleri (yani yüklediği şablon) değerlendirilene kadar çalıştırılmayacağı ve dolayısıyla ngCloak yönergesinin güzel işlevselliğidir.

Benim eğitimli tahminim, sadece ngCloak ile aynı sadeliğe sahip bir yönerge yapmak, sonra derleme işlevinizde yapmak istediğinizi yapmak olacaktır. :) Yönergeyi uygulamanızın kök öğesine yerleştirin. Direktifi myOnload gibi bir şey çağırabilir ve onu my-onload niteliği olarak kullanabilirsiniz. Derleme işlevi, şablon derlendikten sonra (ifadeler değerlendirilir ve alt şablonlar yüklenir) çalıştırılır.

DÜZENLE, 23 saat sonra: Tamam, bu yüzden biraz araştırma yaptım ve kendi sorumu da sordum . Sorduğum soru dolaylı olarak bu soruyla ilgiliydi ama tesadüfen beni bu soruyu çözen cevaba götürdü.

Cevap, basit bir yönerge oluşturup kodunuzu yönergenin link işlevine koyabilmenizdir; bu işlev (çoğu kullanım durumu için aşağıda açıklanmıştır) öğeniz hazır / yüklendiğinde çalışacaktır. Dayanarak derleme ve bağlantı fonksiyonları infaz edildiği düzenin Josh'un açıklaması ,

bu işarete sahipseniz:

<div directive1>
  <div directive2>
    <!-- ... -->
  </div>
</div>

Ardından AngularJS, yönerge işlevlerini belirli bir sırayla çalıştırarak yönergeleri oluşturur:

directive1: compile
  directive2: compile
directive1: controller
directive1: pre-link
  directive2: controller
  directive2: pre-link
  directive2: post-link
directive1: post-link

Varsayılan olarak düz bir "bağlantı" işlevi bir bağlantı sonrası işlevidir, bu nedenle dış yönergenizin1 bağlantı işlevi, iç yönergenin2 bağlantı işlevi çalışana kadar çalışmayacaktır. Bu nedenle bağlantı sonrası yalnızca DOM manipülasyonu yapmanın güvenli olduğunu söylüyoruz. Bu nedenle, orijinal soruya doğru, dış yönergenin link işlevinden child yönergesinin iç html'sine erişmede herhangi bir sorun olmamalıdır, ancak yukarıda belirtildiği gibi dinamik olarak eklenen içerikler derlenmelidir.

Bundan, her şey hazır / derlendiğinde / bağlandığında / yüklendiğinde kodumuzu çalıştırmak için basitçe bir direktif oluşturabileceğimiz sonucuna varabiliriz:

    app.directive('ngElementReady', [function() {
        return {
            priority: -1000, // a low number so this directive loads after all other directives have loaded. 
            restrict: "A", // attribute only
            link: function($scope, $element, $attributes) {
                console.log(" -- Element ready!");
                // do what you want here.
            }
        };
    }]);

Şimdi yapabileceğiniz şey, ngElementReady direktifini uygulamanın kök öğesine koymaktır ve yüklendiğinde ateşlenecektir console.log:

<body data-ng-app="MyApp" data-ng-element-ready="">
   ...
   ...
</body>

Bu kadar basit! Sadece basit bir yönerge hazırlayın ve kullanın. ;)

Ekleyerek bir ifadeyi (yani bir işlevi) çalıştırabilmesi için daha da özelleştirebilirsiniz $scope.$eval($attributes.ngElementReady);:

    app.directive('ngElementReady', [function() {
        return {
            priority: Number.MIN_SAFE_INTEGER, // execute last, after all other directives if any.
            restrict: "A",
            link: function($scope, $element, $attributes) {
                $scope.$eval($attributes.ngElementReady); // execute the expression in the attribute.
            }
        };
    }]);

O zaman herhangi bir öğe üzerinde kullanabilirsiniz:

<body data-ng-app="MyApp" data-ng-controller="BodyCtrl" data-ng-element-ready="bodyIsReady()">
    ...
    <div data-ng-element-ready="divIsReady()">...<div>
</body>

Öğenizin altında bulunduğu kapsamda (denetleyicide) tanımlanmış işlevlerinizin (örn. BodyIsReady ve divIsReady) olduğundan emin olun.

Uyarılar: Bunun çoğu durumda işe yarayacağını söyledim . NgRepeat ve ngIf gibi belirli yönergeleri kullanırken dikkatli olun. Kendi kapsamlarını yaratırlar ve direktifiniz ateşlenmeyebilir. Örneğin, yeni ngElementReady yönergemizi ngIf'e sahip olan bir öğeye koyarsanız ve ngIf'in durumu false olarak değerlendirilirse, ngElementReady yönergemiz yüklenmez. Veya, örneğin, yeni ngElementReady yönergemizi bir ngInclude yönergesi olan bir öğeye koyarsanız, yönergemiz ngInclude için şablon yoksa yüklenmeyecektir. Direktifleri hepsini aynı öğeye koymak yerine iç içe geçirdiğinizden emin olarak bu sorunların bazılarının üstesinden gelebilirsiniz. Örneğin, bunu yaparak:

<div data-ng-element-ready="divIsReady()">
    <div data-ng-include="non-existent-template.html"></div>
<div>

bunun yerine:

<div data-ng-element-ready="divIsReady()" data-ng-include="non-existent-template.html"></div>

NgElementReady yönergesi ikinci örnekte derlenecek, ancak bağlantı işlevi çalıştırılmayacaktır. Not: Yönergeler her zaman derlenir, ancak yukarıdaki gibi belirli senaryolara bağlı olarak bağlantı işlevleri her zaman çalıştırılmaz.

DÜZENLE, birkaç dakika sonra:

Oh, ve soruyu tam olarak cevaplamak için, şimdi $emitveya $broadcastolayınızı ng-element-readyöznitelikte yürütülen ifade veya işlevden yapabilirsiniz . :) Örneğin:

<div data-ng-element-ready="$emit('someEvent')">
    ...
<div>

DÜZENLE, hatta birkaç dakika sonra:

@ satchmorun'un cevabı da işe yarıyor, ancak yalnızca ilk yükleme için. İşte bağlantı işlevleri ve diğerleri dahil olmak üzere şeylerin yürütülme sırasını açıklayan çok kullanışlı bir SO sorusuapp.run . Bu nedenle, kullanım durumunuza bağlı app.runolarak iyi olabilir, ancak belirli öğeler için geçerli olmayabilir, bu durumda bağlantı işlevleri daha iyidir.

EDIT, beş ay sonra, 17 Ekim 08:11 PST:

Bu, eşzamansız olarak yüklenen bölümlerle çalışmaz. Parçalarınıza defter tutma eklemeniz gerekir (örneğin, bir yol, her bir parçanın içeriğinin ne zaman yüklendiğini takip etmesini sağlamak ve ardından bir olay yayınlamaktır, böylece üst kapsam, kaç parçanın yüklendiğini sayabilir ve sonunda ne yapması gerektiğini yapabilir. tüm parçalar yüklendikten sonra yapın).

DÜZENLE, 23 Ekim 22:52 PST:

Bir resim yüklendiğinde bazı kodların ateşlenmesi için basit bir yönerge hazırladım:

/*
 * This img directive makes it so that if you put a loaded="" attribute on any
 * img element in your app, the expression of that attribute will be evaluated
 * after the images has finished loading. Use this to, for example, remove
 * loading animations after images have finished loading.
 */
  app.directive('img', function() {
    return {
      restrict: 'E',
      link: function($scope, $element, $attributes) {
        $element.bind('load', function() {
          if ($attributes.loaded) {
            $scope.$eval($attributes.loaded);
          }
        });
      }
    };
  });

DÜZENLE, 24 Ekim 00:48 PST:

Orijinal ngElementReadyyönergemi geliştirdim ve olarak yeniden adlandırdım whenReady.

/*
 * The whenReady directive allows you to execute the content of a when-ready
 * attribute after the element is ready (i.e. done loading all sub directives and DOM
 * content except for things that load asynchronously like partials and images).
 *
 * Execute multiple expressions by delimiting them with a semi-colon. If there
 * is more than one expression, and the last expression evaluates to true, then
 * all expressions prior will be evaluated after all text nodes in the element
 * have been interpolated (i.e. {{placeholders}} replaced with actual values). 
 *
 * Caveats: if other directives exists on the same element as this directive
 * and destroy the element thus preventing other directives from loading, using
 * this directive won't work. The optimal way to use this is to put this
 * directive on an outer element.
 */
app.directive('whenReady', ['$interpolate', function($interpolate) {
  return {
    restrict: 'A',
    priority: Number.MIN_SAFE_INTEGER, // execute last, after all other directives if any.
    link: function($scope, $element, $attributes) {
      var expressions = $attributes.whenReady.split(';');
      var waitForInterpolation = false;

      function evalExpressions(expressions) {
        expressions.forEach(function(expression) {
          $scope.$eval(expression);
        });
      }

      if ($attributes.whenReady.trim().length == 0) { return; }

      if (expressions.length > 1) {
        if ($scope.$eval(expressions.pop())) {
          waitForInterpolation = true;
        }
      }

      if (waitForInterpolation) {
        requestAnimationFrame(function checkIfInterpolated() {
          if ($element.text().indexOf($interpolate.startSymbol()) >= 0) { // if the text still has {{placeholders}}
            requestAnimationFrame(checkIfInterpolated);
          }
          else {
            evalExpressions(expressions);
          }
        });
      }
      else {
        evalExpressions(expressions);
      }
    }
  }
}]);

Örneğin, someFunctionbir öğe yüklendiğinde ve {{placeholders}}henüz değiştirilmediğinde ateşlemek için bunu şu şekilde kullanın :

<div when-ready="someFunction()">
  <span ng-repeat="item in items">{{item.property}}</span>
</div>

someFunctiontüm item.propertyyer tutucular değiştirilmeden önce çağrılacaktır .

İstediğiniz kadar ifadeyi değerlendirin ve son ifadeyi şu şekilde değerlendirilmesini truebekleyin {{placeholders}}:

<div when-ready="someFunction(); anotherFunction(); true">
  <span ng-repeat="item in items">{{item.property}}</span>
</div>

someFunctionve değiştirildikten anotherFunctionsonra kovulacak {{placeholders}}.

Bu, gelecekteki değişikliklerde değil, yalnızca bir öğe ilk yüklendiğinde çalışır. Yer $digesttutucular başlangıçta değiştirildikten sonra bir devam ederse , istenildiği gibi çalışmayabilir (bir $ özet, verilerin değişmesi durana kadar 10 kez gerçekleşebilir). Kullanım durumlarının büyük çoğunluğu için uygun olacaktır.

DÜZENLE, 31 Ekim 19:26 PST:

Pekala, bu muhtemelen benim son ve son güncellemem. Bu muhtemelen oradaki kullanım durumlarının 99.999'u için işe yarayacaktır:

/*
 * The whenReady directive allows you to execute the content of a when-ready
 * attribute after the element is ready (i.e. when it's done loading all sub directives and DOM
 * content). See: /programming/14968690/sending-event-when-angular-js-finished-loading
 *
 * Execute multiple expressions in the when-ready attribute by delimiting them
 * with a semi-colon. when-ready="doThis(); doThat()"
 *
 * Optional: If the value of a wait-for-interpolation attribute on the
 * element evaluates to true, then the expressions in when-ready will be
 * evaluated after all text nodes in the element have been interpolated (i.e.
 * {{placeholders}} have been replaced with actual values).
 *
 * Optional: Use a ready-check attribute to write an expression that
 * specifies what condition is true at any given moment in time when the
 * element is ready. The expression will be evaluated repeatedly until the
 * condition is finally true. The expression is executed with
 * requestAnimationFrame so that it fires at a moment when it is least likely
 * to block rendering of the page.
 *
 * If wait-for-interpolation and ready-check are both supplied, then the
 * when-ready expressions will fire after interpolation is done *and* after
 * the ready-check condition evaluates to true.
 *
 * Caveats: if other directives exists on the same element as this directive
 * and destroy the element thus preventing other directives from loading, using
 * this directive won't work. The optimal way to use this is to put this
 * directive on an outer element.
 */
app.directive('whenReady', ['$interpolate', function($interpolate) {
  return {
    restrict: 'A',
    priority: Number.MIN_SAFE_INTEGER, // execute last, after all other directives if any.
    link: function($scope, $element, $attributes) {
      var expressions = $attributes.whenReady.split(';');
      var waitForInterpolation = false;
      var hasReadyCheckExpression = false;

      function evalExpressions(expressions) {
        expressions.forEach(function(expression) {
          $scope.$eval(expression);
        });
      }

      if ($attributes.whenReady.trim().length === 0) { return; }

    if ($attributes.waitForInterpolation && $scope.$eval($attributes.waitForInterpolation)) {
        waitForInterpolation = true;
    }

      if ($attributes.readyCheck) {
        hasReadyCheckExpression = true;
      }

      if (waitForInterpolation || hasReadyCheckExpression) {
        requestAnimationFrame(function checkIfReady() {
          var isInterpolated = false;
          var isReadyCheckTrue = false;

          if (waitForInterpolation && $element.text().indexOf($interpolate.startSymbol()) >= 0) { // if the text still has {{placeholders}}
            isInterpolated = false;
          }
          else {
            isInterpolated = true;
          }

          if (hasReadyCheckExpression && !$scope.$eval($attributes.readyCheck)) { // if the ready check expression returns false
            isReadyCheckTrue = false;
          }
          else {
            isReadyCheckTrue = true;
          }

          if (isInterpolated && isReadyCheckTrue) { evalExpressions(expressions); }
          else { requestAnimationFrame(checkIfReady); }

        });
      }
      else {
        evalExpressions(expressions);
      }
    }
  };
}]);

Bunu böyle kullan

<div when-ready="isReady()" ready-check="checkIfReady()" wait-for-interpolation="true">
   isReady will fire when this {{placeholder}} has been evaluated
   and when checkIfReady finally returns true. checkIfReady might
   contain code like `$('.some-element').length`.
</div>

Tabii ki, muhtemelen optimize edilebilir, ancak bunu öyle bırakacağım. requestAnimationFrame güzel.


3
Tüm bu "veri" önekleriyle gerçekten can sıkıcı. Onları kendim kullanmadığım için mutluyum.
stolsvik

1
@stolsvik heh, evet, en modern tarayıcılarda bunlara gerek yok.
trusktr

49
Bu cevap için harcanan zaman ve çaba için oyu hak ediyor. İyi iş!
GordyD

8
Güzel yanıt, ancak lütfen tüm "Düzenle" satırlarını kaldırmayı ve yanıtınızı biraz yeniden yapılandırmayı düşünün. Düzenleme geçmişine cevabınızın altındaki "düzenlenmiş ..." bağlantısı üzerinden ulaşılabilir ve okurken dikkati dağıtır.
user247702

2
Kaynak kodu gerçekten yardımcı olacaktır. Ve npm'de herkese açık hale getirebilirseniz, bu MÜKEMMEL olur. Gerçekten güzel cevap, gerçekten güzel bir şekilde açıklandı, buna harcanan emeğin miktarı için +1.
tfrascaroli

38

In için docsangular.Module , açıklayan bir giriş var runişlevi:

Enjektörün tüm modülleri yüklemesi bittiğinde yapılması gereken işi kaydetmek için bu yöntemi kullanın.

Dolayısıyla, uygulamanız olan bir modülünüz varsa:

var app = angular.module('app', [/* module dependencies */]);

Modüller yüklendikten sonra şunları çalıştırabilirsiniz:

app.run(function() {
  // Do post-load initialization stuff here
});

DÜZENLEME: Kurtarmaya Manuel Başlatma

Dolayısıyla run, DOM hazır olduğunda ve bağlandığında çağrılmayacağına dikkat çekildi. $injectorTarafından başvurulan modül ng-app, DOM derleme adımından ayrı olan tüm bağımlılıklarını yüklediğinde çağrılır .

El ile başlatmaya bir kez daha baktım ve bu işin püf noktası olması gerekiyor.

Göstermek için bir keman yaptım .

HTML basittir:

<html>
    <body>
        <test-directive>This is a test</test-directive>
    </body>
</html>

Bir ng-app. Ve bazı DOM manipülasyonu yapacak bir direktifim var, böylece işlerin sırasından ve zamanlamasından emin olabiliriz.

Her zamanki gibi bir modül oluşturulur:

var app = angular.module('app', []);

Ve işte direktif:

app.directive('testDirective', function() {
    return {
        restrict: 'E',
        template: '<div class="test-directive"><h1><div ng-transclude></div></h1></div>',
        replace: true,
        transclude: true,
        compile: function() {
            console.log("Compiling test-directive");
            return {
                pre: function() { console.log("Prelink"); },
                post: function() { console.log("Postlink"); }
            };
        }
    };
});

test-directiveEtiketi a divsınıfıyla değiştireceğiz test-directiveve içeriğini bir h1.

Hem bağlantı öncesi hem de sonrası bağlantı işlevlerini döndüren bir derleme işlevi ekledim, böylece bunların ne zaman çalıştığını görebiliriz.

İşte kodun geri kalanı:

// The bootstrapping process

var body = document.getElementsByTagName('body')[0];

// Check that our directive hasn't been compiled

function howmany(classname) {
    return document.getElementsByClassName(classname).length;
}

Herhangi bir şey yapmadan önce test-directive, DOM'da sınıfına sahip hiçbir öğe olmamalı ve işimiz bittikten sonra 1 olmalıdır.

console.log('before (should be 0):', howmany('test-directive'));

angular.element(document).ready(function() {
    // Bootstrap the body, which loades the specified modules
    // and compiled the DOM.
    angular.bootstrap(body, ['app']);

    // Our app is loaded and the DOM is compiled
    console.log('after (should be 1):', howmany('test-directive'));
});

Oldukça basit. Belge hazır olduğunda, angular.bootstrapuygulamanızın kök öğesi ve bir dizi modül adı ile arayın .

Aslında, modüle bir runişlevapp eklerseniz, herhangi bir derleme gerçekleşmeden önce çalıştığını görürsünüz.

Keman çalar ve konsolu izlerseniz, şunları görürsünüz:

before (should be 0): 0 
Compiling test-directive 
Prelink
Postlink
after (should be 1): 1 <--- success!

2
teşekkürler @satchmorun! ancak run () bağlantı parçasının bitiminden önce yürütülür - sadece bazı console.logs ile doğruladı.
Lior

kendimi merak ediyordum ... Bazı jQuery DOM eklentilerini uygulamak için ateşleyen bir direktifim var, direktiften runönce ateşleniyor ve çalıştırıldığında html hepsi orada değil
charlietfl

@charlietfl - Manuel önyüklemeye biraz girdim ve aslında sorunun aradığını elde etmenin oldukça kolay bir yolu. Orijinal cevabıma oldukça uzun bir düzenleme ekledim.
satchmorun

5
$timeout( initMyPlugins,0)
charlietfl

@satchmorun, bu takibe bakın: stackoverflow.com/questions/14989161/…
Lior

16

Angular, bir sayfanın yüklenmesi bittiğinde sinyal vermenin bir yolunu sağlamamıştır, bunun nedeni "tamamlandı" nın uygulamanıza bağlı olması olabilir . Örneğin, hiyerarşik parça ağacınız varsa, biri diğerlerini yüklüyor. "Bitir", hepsinin yüklenmiş olduğu anlamına gelir. Herhangi bir çerçeve, kodunuzu analiz etmekte ve her şeyin yapıldığını veya hala beklendiğini anlamakta zorlanacaktır. Bunun için, bunu kontrol etmek ve belirlemek için uygulamaya özel mantık sağlamanız gerekir.


15

Açısal başlatmanın ne zaman tamamlandığını değerlendirmede nispeten doğru olan bir çözüm buldum.

Yönerge:

.directive('initialisation',['$rootScope',function($rootScope) {
            return {
                restrict: 'A',
                link: function($scope) {
                    var to;
                    var listener = $scope.$watch(function() {
                        clearTimeout(to);
                        to = setTimeout(function () {
                            console.log('initialised');
                            listener();
                            $rootScope.$broadcast('initialised');
                        }, 50);
                    });
                }
            };
        }]);

Bu daha sonra bodyöğeye bir öznitelik olarak eklenebilir ve daha sonra kullanım için dinlenebilir$scope.$on('initialised', fn)

Artık $ özet döngüsü olmadığında uygulamanın başlatıldığını varsayarak çalışır. $ watch her özet döngüsü çağrılır ve böylece bir zamanlayıcı başlatılır (setTimeout $ timeout değil, böylece yeni bir özet döngüsü tetiklenmez). Zaman aşımı süresi içinde bir özet döngüsü gerçekleşmezse, uygulamanın başlatıldığı varsayılır.

Açıkçası, satchmoruns çözümü kadar doğru değil (çünkü bir özet döngüsü zaman aşımından daha uzun sürüyor olabilir) ancak benim çözümüm, yönetimi çok daha kolay hale getiren modülleri takip etmenizi gerektirmiyor (özellikle büyük projeler için) ). Her neyse, ihtiyaçlarımı karşılayacak kadar doğru görünüyor. Umarım yardımcı olur.


Mükemmel çözüm. Bir veya iki sıkıştırılmış dosyadaki tüm kodun çok iyi çalıştığı projeler için.
merqlove

1
Bu harika bir çözüm. Jquery'de çok sayıda kodunuz varsa ve kodu adım adım açısal hale getirmeye çalışıyorsanız, bu çok mantıklıdır.
Mangesh Pimpalkar

11

Angular UI Router kullanıyorsanız , $viewContentLoadedolayı dinleyebilirsiniz .

"$ viewContentLoaded - DOM oluşturulduktan sonra görünüm yüklendikten sonra tetiklenir. Görünümün " $ kapsamı "etkinliği yayar." - Bağlantı

$scope.$on('$viewContentLoaded', 
function(event){ ... });

3
$ kapsam. $ watch ('$ viewContentLoaded', function () benim için hile yaptı
Louis XIV

2
"Olman gereken" için olumsuz oy verildi. Ya "Angular yerine React kullanıyorsanız (ki olmalısınız) ..." dersem? Bu ekosistem IMHO'da pek bir tavır değil.
Valentin Waeselynck

@ValentinWaeselynck kesinlikle haklısınız. Önyargımı ortadan kaldırmak için cevabımı düzenledim.
Jordan Skole

1
Benim için çalıştı! Teşekkür ederim. Aslında bunu çalıştırma fonksiyonuma ekledim, sonra $ kapsamını $ rootScope olarak değiştirdim.
JDavies

2
Angular University'nin farklı bir cevapta işaret ettiği gibi, $ viewContentLoaded orjinal olarak orada bulunmamış olabilir, ancak şimdi yerleşik ngRoute sağlayıcısında tam olarak aynı şekilde çalışıyor. Bunu göz önünde bulundurarak, bence bu, gelecekteki birçok okuyucunun (çoğu?) Arayacağı hızlı, basit, okunabilir yanıt.
Kevin Crumley

3

JQuery ile açısal DOM manipülasyonunu gözlemliyorum ve uygulamam için bir son belirledim (uygulama özetim için ihtiyaç duyduğum bir tür önceden tanımlanmış ve tatmin edici durum), örneğin ng-tekrarlayıcımın 7 sonuç üretmesini bekliyorum ve orada i bu amaç için setInterval yardımıyla bir gözlem fonksiyonu kuracaktır.

$(document).ready(function(){

  var interval = setInterval(function(){

  if($("article").size() == 7){
     myFunction();
     clearInterval(interval);
  }

  },50);

});

3
Ben bunu yapmam. Bir şeylerin olup olmadığını kontrol etmek için aralıkları kullanmak iyi bir uygulama değildir, ölçeklenemez ve bir şeyleri gerçekleştirmenin başka yolları da vardır. Zamanlayıcılar, içerik veya sonuçlar hazır olduğunda "tahmin etmek" için değil, belirli bir süre sonra gerçekleşmesi gereken somut görevleri yapmak içindir.
dudewad

Açısal platforma karşı bir jquery zamanlayıcı kullanmanın üretkenlik karşıtı - açısal bir zaman aşımı sınıfına sahip olduğundan bahsetmiyorum bile, aksi takdirde iki çerçeveyi birleştiriyorsunuz ve çok hızlı bir şekilde kafa karıştırıcı hale geliyor.
dudewad

3

NgRoute modülünü kullanmıyorsanız , yani $ viewContentLoaded olayınız yoksa .

Başka bir yönerge yöntemi kullanabilirsiniz:

    angular.module('someModule')
        .directive('someDirective', someDirective);

    someDirective.$inject = ['$rootScope', '$timeout']; //Inject services

    function someDirective($rootScope, $timeout){
        return {
            restrict: "A",
            priority: Number.MIN_SAFE_INTEGER, //Lowest priority
            link    : function(scope, element, attr){
                $timeout(
                    function(){
                        $rootScope.$emit("Some:event");
                    }
                );
            }
        };
    }

Trusktr'ın cevabına göre en düşük önceliğe sahip. Artı $ zaman aşımı , Angular'ın geri arama çalıştırılmadan önce tüm olay döngüsünden geçmesine neden olur.

$ rootScope kullanıldı, çünkü direktifin uygulamanın herhangi bir kapsamına yerleştirilmesine izin veriyor ve sadece gerekli dinleyicileri bilgilendiriyor.

$ rootScope. $ emit tüm $ rootScope için bir olayı tetikler. $ sadece dinleyicilerde. İlginç olan kısım, $ rootScope. $ Yayınının tüm $ rootScope. $ On ve $ kapsam. $ On dinleyicileri Kaynak


2

Angular ekibine ve bu Github sorununa göre :

şimdi sırasıyla ng-view ve ng-include'de yayınlanan $ viewContentLoaded ve $ includeContentLoaded olaylarına sahibiz. Bence bu, derlemeyi ne zaman bitirdiğimizi öğrenmeye en yakın şey.

Buna dayanarak, şu anda bunu güvenilir bir şekilde yapmak mümkün görünmüyor , aksi takdirde Angular olayı kutudan çıkarırdı.

Uygulamanın önyüklenmesi, özet döngüsünün kök kapsamda çalıştırılması anlamına gelir ve ayrıca bir özet döngüsü tamamlandı olayı yoktur.

Angular 2 tasarım belgelerine göre :

Birden çok özütleme nedeniyle, modelin kararlı olduğunu bileşene belirlemek ve bildirmek imkansızdır. Bunun nedeni, bildirimin verileri daha fazla değiştirebilmesidir, bu da bağlama işlemini yeniden başlatabilir.

Buna göre bunun mümkün olmaması, Angular 2'de yeniden yazmaya gitme kararının alınmasının nedenlerinden biridir.


2

Yönlendirme yoluyla gelen ana parçadan sonra / tarafından yüklenen bir parçam vardı.

Bu alt bölüm yüklendikten sonra bir işlev çalıştırmam gerekiyordu ve yeni bir yönerge yazmak istemedim ve arsızca kullanabileceğinizi anladım. ngIf

Üst kısmi denetleyici:

$scope.subIsLoaded = function() { /*do stuff*/; return true; };

Alt bölümün HTML'si

<element ng-if="subIsLoaded()"><!-- more html --></element>

1

Sunucu tarafı verileriyle (JSP, PHP) JS oluşturmak istiyorsanız, denetleyiciniz yüklendiğinde otomatik olarak yüklenecek olan bir hizmete mantığınızı ekleyebilirsiniz.

Ek olarak, tüm direktiflerin derlenmesi / bağlanması tamamlandığında tepki vermek istiyorsanız, yukarıdaki başlatma mantığına önerilen uygun çözümleri ekleyebilirsiniz.

module.factory('YourControllerInitService', function() {

    // add your initialization logic here

    // return empty service, because it will not be used
    return {};
});


module.controller('YourController', function (YourControllerInitService) {
});

0

Bunların hepsi harika çözümler, Ancak, şu anda Yönlendirme kullanıyorsanız, o zaman bu çözümü en kolay ve gereken kod miktarı olarak buldum. Rotayı tetiklemeden önce bir sözün tamamlanmasını beklemek için 'çözme' özelliğini kullanma. Örneğin

$routeProvider
.when("/news", {
    templateUrl: "newsView.html",
    controller: "newsController",
    resolve: {
        message: function(messageService){
            return messageService.getMessage();
    }
}

})

Belgelerin tamamı için burayı tıklayın - K. Scott Allen'a Kredi Verin


0

bu örnekle size yardımcı olabilir miyim?

Özel fantezi kutusunda, enterpolasyonlu değerlere sahip içerikleri gösteriyorum.

hizmette, "açık" fantezi kutusu yönteminde

open: function(html, $compile) {
        var el = angular.element(html);
     var compiledEl = $compile(el);
        $.fancybox.open(el); 
      }

$ derleme derlenmiş verileri döndürür. derlenmiş verileri kontrol edebilirsiniz

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.