Mengirim acara ketika AngularJS selesai memuat

114

Ingin tahu apa cara terbaik untuk mendeteksi selesainya pemuatan / bootstrap halaman, ketika semua arahan selesai kompilasi / penautan.

Adakah acara yang sudah ada? Haruskah saya membebani fungsi bootstrap secara berlebihan?

Lior
sumber

Jawaban:

204

Hanya firasat: mengapa tidak melihat bagaimana arahan ngCloak melakukannya? Jelas direktif ngCloak berhasil menampilkan konten setelah banyak hal dimuat. Saya yakin melihat ngCloak akan mengarah ke jawaban yang tepat ...

EDIT 1 jam kemudian: Ok, saya melihat ngCloak dan itu sangat singkat. Hal ini secara jelas menyiratkan bahwa fungsi kompilasi tidak akan dijalankan hingga ekspresi {{template}} telah dievaluasi (yaitu template yang dimuatnya), dengan demikian fungsionalitas yang bagus dari direktif ngCloak.

Tebakan saya yang terpelajar adalah hanya membuat arahan dengan kesederhanaan ngCloak yang sama, lalu dalam fungsi kompilasi Anda lakukan apa pun yang ingin Anda lakukan. :) Tempatkan direktif pada elemen root aplikasi Anda. Anda dapat memanggil direktif seperti myOnload dan menggunakannya sebagai atribut my-onload. Fungsi kompilasi akan dijalankan setelah template dikompilasi (ekspresi dievaluasi dan sub-template dimuat).

EDIT, 23 jam kemudian: Oke, jadi saya melakukan riset, dan saya juga mengajukan pertanyaan saya sendiri . Pertanyaan yang saya ajukan secara tidak langsung terkait dengan pertanyaan ini, tetapi secara kebetulan membawa saya ke jawaban yang memecahkan pertanyaan ini.

Jawabannya adalah Anda dapat membuat direktif sederhana dan meletakkan kode Anda di fungsi tautan direktif, yang (untuk sebagian besar kasus penggunaan, dijelaskan di bawah) akan berjalan ketika elemen Anda siap / dimuat. Berdasarkan deskripsi Josh tentang urutan di mana fungsi kompilasi dan tautan dijalankan ,

jika Anda memiliki markup ini:

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

Kemudian AngularJS akan membuat direktif dengan menjalankan fungsi direktif dalam urutan tertentu:

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

Secara default, fungsi "link" lurus adalah post-link, sehingga fungsi link outer directive1 Anda tidak akan berjalan hingga fungsi link inner directive2 dijalankan. Itulah mengapa kami mengatakan bahwa manipulasi DOM hanya aman dilakukan di tautan pos. Jadi terhadap pertanyaan awal, seharusnya tidak ada masalah mengakses html bagian dalam direktif anak dari fungsi tautan direktif luar, meskipun konten yang dimasukkan secara dinamis harus dikompilasi, seperti yang dikatakan di atas.

Dari sini kita dapat menyimpulkan bahwa kita dapat membuat arahan untuk mengeksekusi kode kita ketika semuanya sudah siap / dikompilasi / ditautkan / dimuat:

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

Sekarang yang dapat Anda lakukan adalah meletakkan direktif ngElementReady ke elemen root aplikasi, dan console.logakan aktif saat dimuat:

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

Sesederhana itu! Buat saja petunjuk sederhana dan gunakan itu. ;)

Anda selanjutnya dapat menyesuaikannya sehingga dapat mengeksekusi ekspresi (yaitu fungsi) dengan menambahkannya $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.
            }
        };
    }]);

Kemudian Anda dapat menggunakannya di elemen apa pun:

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

Pastikan Anda memiliki fungsi Anda (misalnya bodyIsReady dan divIsReady) yang ditentukan dalam cakupan (di pengontrol) tempat elemen Anda berada.

Peringatan: Saya mengatakan ini akan berhasil untuk banyak kasus. Hati-hati saat menggunakan arahan tertentu seperti ngRepeat dan ngIf. Mereka membuat ruang lingkupnya sendiri, dan arahan Anda tidak boleh menyala. Misalnya jika Anda meletakkan direktif ngElementReady baru kami pada elemen yang juga memiliki ngIf, dan kondisi ngIf bernilai false, maka direktif ngElementReady kami tidak akan dimuat. Atau, misalnya, jika Anda meletakkan direktif ngElementReady baru kami pada elemen yang juga memiliki direktif ngInclude, direktif kami tidak akan dimuat jika template untuk ngInclude tidak ada. Anda dapat mengatasi beberapa masalah ini dengan memastikan Anda menyusun arahan daripada menempatkan semuanya pada elemen yang sama. Misalnya, dengan melakukan ini:

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

alih-alih ini:

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

Direktif ngElementReady akan dikompilasi dalam contoh terakhir, tetapi fungsi tautannya tidak akan dijalankan. Catatan: direktif selalu dikompilasi, tetapi fungsi tautannya tidak selalu dijalankan tergantung pada skenario tertentu seperti di atas.

EDIT, beberapa menit kemudian:

Oh, dan untuk sepenuhnya menjawab pertanyaan itu, Anda sekarang dapat $emitatau $broadcastacara Anda dari ekspresi atau fungsi yang dijalankan di ng-element-readyatribut. :) Misalnya:

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

EDIT, bahkan beberapa menit kemudian:

Jawaban @ satchmorun juga berfungsi, tetapi hanya untuk pemuatan awal. Berikut adalah pertanyaan SO yang sangat berguna yang menjelaskan urutan hal-hal yang dijalankan termasuk fungsi tautan app.run,, dan lainnya. Jadi, bergantung pada kasus penggunaan Anda, app.runmungkin bagus, tetapi tidak untuk elemen tertentu, dalam hal ini fungsi tautan lebih baik.

EDIT, lima bulan kemudian, 17 Okt pukul 8:11 PST:

Ini tidak berfungsi dengan parsial yang dimuat secara asinkron. Anda harus menambahkan pembukuan ke dalam parsial Anda (misalnya salah satu cara adalah membuat setiap pelacakan parsial ketika isinya selesai memuat, lalu keluarkan acara sehingga cakupan induk dapat menghitung berapa banyak parsial yang telah dimuat dan akhirnya melakukan apa yang diperlukan lakukan setelah semua parsial dimuat).

EDIT, 23 Okt pukul 10:52 malam PST:

Saya membuat arahan sederhana untuk mengaktifkan beberapa kode saat gambar dimuat:

/*
 * 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);
          }
        });
      }
    };
  });

EDIT, 24 Okt pukul 12:48 PST:

Saya meningkatkan ngElementReadyarahan asli saya dan menamainya kembali menjadi 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);
      }
    }
  }
}]);

Misalnya, gunakan seperti ini untuk mengaktifkan someFunctionsaat elemen dimuat dan {{placeholders}}belum diganti:

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

someFunctionakan dipanggil sebelum semua item.propertyplaceholder diganti.

Evaluasi ekspresi sebanyak yang Anda inginkan, dan buat ekspresi terakhir truemenunggu untuk {{placeholders}}dievaluasi seperti ini:

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

someFunctiondan anotherFunctionakan dipecat setelah {{placeholders}}diganti.

Ini hanya berfungsi saat pertama kali elemen dimuat, bukan pada perubahan di masa mendatang. Ini mungkin tidak berfungsi seperti yang diinginkan jika $digestterus terjadi setelah placeholder awalnya diganti (intisari $ dapat terjadi hingga 10 kali hingga data berhenti berubah). Ini akan cocok untuk sebagian besar kasus penggunaan.

EDIT, 31 Okt pukul 19:26 PST:

Baiklah, ini mungkin pembaruan terakhir dan terakhir saya. Ini mungkin akan berfungsi untuk 99,999 kasus penggunaan di luar sana:

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

Gunakan seperti ini

<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>

Tentu saja, ini mungkin dapat dioptimalkan, tetapi saya akan berhenti di situ. requestAnimationFrame bagus.

trusktr
sumber
3
Benar-benar menjengkelkan dengan semua awalan "data-" itu. Saya senang saya tidak menggunakannya sendiri.
stolsvik
1
@stolsvik heh, ya, di peramban terbaru, mereka tidak diperlukan.
trusktr
49
Layak mendapatkan suara untuk jumlah waktu dan upaya yang dimasukkan ke dalam jawaban ini. Kerja bagus!
GordyD
8
Jawaban bagus, tapi mohon pertimbangkan untuk menghapus semua baris "Edit" dan sedikit mengubah struktur jawaban Anda. Riwayat edit tersedia melalui tautan "diedit ..." di bagian bawah jawaban Anda, dan ini mengganggu saat membaca.
pengguna247702
2
Kode sumber akan sangat membantu. Dan jika Anda dapat mempublikasikannya pada npm, itu SEMPURNA. Jawaban yang sangat bagus, dijelaskan dengan sangat baik, +1 untuk jumlah upaya yang dilakukan untuk ini.
tfrascaroli
38

Di dokumen untukangular.Module , ada entri yang menjelaskan runfungsinya:

Gunakan metode ini untuk mendaftarkan pekerjaan yang harus dilakukan ketika injektor selesai memuat semua modul.

Jadi, jika Anda memiliki beberapa modul yang merupakan aplikasi Anda:

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

Anda dapat menjalankan sesuatu setelah modul dimuat dengan:

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

EDIT: Inisialisasi Manual untuk penyelamatan

Jadi telah ditunjukkan bahwa runtidak dipanggil ketika DOM sudah siap dan ditautkan. Ini dipanggil ketika $injectoruntuk modul yang dirujuk oleh ng-apptelah memuat semua dependensinya, yang terpisah dari langkah kompilasi DOM.

Saya melihat lagi inisialisasi manual , dan tampaknya ini akan berhasil.

Saya telah membuat biola untuk diilustrasikan .

HTMLnya sederhana:

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

Perhatikan kekurangan file ng-app. Dan saya memiliki arahan yang akan melakukan beberapa manipulasi DOM, sehingga kami dapat memastikan urutan dan waktu segala sesuatunya.

Seperti biasa, modul dibuat:

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

Dan inilah arahannya:

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"); }
            };
        }
    };
});

Kami akan mengganti test-directivetag dengan divkelas test-directive, dan membungkus isinya dalamh1 .

Saya telah menambahkan fungsi kompilasi yang mengembalikan fungsi tautan pra dan pasca sehingga kita dapat melihat kapan hal-hal ini berjalan.

Berikut kode lainnya:

// 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;
}

Sebelum kita melakukan apa pun, seharusnya tidak ada elemen dengan kelas test-directivedi DOM, dan setelah kita selesai harus ada 1.

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

Ini sangat mudah. Jika dokumen sudah siap, panggilangular.bootstrap dengan elemen root aplikasi Anda dan larik nama modul.

Faktanya, jika Anda melampirkan runfungsi ke appmodul , Anda akan melihatnya dijalankan sebelum kompilasi apa pun dilakukan.

Jika Anda menjalankan biola dan menonton konsol, Anda akan melihat yang berikut ini:

before (should be 0): 0 
Compiling test-directive 
Prelink
Postlink
after (should be 1): 1 <--- success!
satchmorun
sumber
2
terima kasih @satchorun! tetapi run () dieksekusi sebelum akhir bagian yang menghubungkan - cukup memverifikasinya dengan beberapa console.logs.
Lior
penasaran dengan diri saya sendiri ... Saya memiliki arahan yang dijalankan untuk mengimplementasikan beberapa plugin jQuery DOM, rundiaktifkan sebelum arahan dan ketika dijalankan, html tidak semuanya ada
charlietfl
@charlietfl - Saya menggali sedikit ke dalam bootstrap manual, dan ini sebenarnya cara yang cukup mudah untuk mendapatkan apa yang dicari pertanyaan tersebut. Saya telah menambahkan suntingan yang cukup panjang ke jawaban asli saya.
satchmorun
5
saya menemukan bahwa menggunakan $timeout( initMyPlugins,0)karya dalam arahan saya, semua html yang saya butuhkan ada di sana
charlietfl
@satchmorun, lihat tindak lanjut ini: stackoverflow.com/questions/14989161/…
Lior
16

Angular belum menyediakan cara untuk memberi sinyal ketika halaman selesai dimuat, mungkin karena "selesai" bergantung pada aplikasi Anda . Misalnya, jika Anda memiliki pohon hierarki parsial, satu memuat yang lain. "Selesai" berarti semuanya telah dimuat. Kerangka kerja apa pun akan kesulitan menganalisis kode Anda dan memahami bahwa semuanya telah selesai, atau masih menunggu. Untuk itu, Anda harus menyediakan logika khusus aplikasi untuk memeriksa dan menentukannya.

Lior
sumber
14

Saya telah menemukan solusi yang relatif akurat dalam mengevaluasi ketika inisialisasi sudut selesai.

Arahannya adalah:

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

Itu kemudian dapat ditambahkan sebagai atribut ke bodyelemen dan kemudian didengarkan untuk digunakan$scope.$on('initialised', fn)

Ia bekerja dengan mengasumsikan bahwa aplikasi dijalankan ketika tidak ada lagi siklus $ digest. $ watch dipanggil setiap siklus intisari dan timer dimulai (setTimeout bukan $ timeout sehingga siklus intisari baru tidak dipicu). Jika siklus intisari tidak terjadi dalam waktu tunggu maka aplikasi dianggap telah diinisialisasi.

Ini jelas tidak seakurat solusi satchmoruns (karena mungkin saja siklus intisari membutuhkan waktu lebih lama dari batas waktu) tetapi solusi saya tidak mengharuskan Anda untuk melacak modul yang membuatnya lebih mudah untuk dikelola (terutama untuk proyek yang lebih besar ). Bagaimanapun, tampaknya cukup akurat untuk kebutuhan saya. Semoga membantu.

Theo
sumber
Solusi luar biasa. Untuk proyek ketika semua kode dalam satu atau dua file terkompresi bekerja dengan sangat baik.
merqlove
1
Ini adalah solusi yang luar biasa Jika Anda memiliki banyak kode di jquery dan Anda mencoba untuk mengubah kode menjadi langkah demi langkah sudut, ini sangat masuk akal.
Mangesh Pimpalkar
11

Jika Anda menggunakan Angular UI Router , Anda dapat mendengarkan $viewContentLoadedacara tersebut.

"$ viewContentLoaded - diaktifkan setelah tampilan dimuat, setelah DOM dirender . '$ scope' dari tampilan memancarkan acara." - Tautan

$scope.$on('$viewContentLoaded', 
function(event){ ... });
Jordan Skole
sumber
3
$ scope. $ watch ('$ viewContentLoaded', function () membuat trik untuk saya
Louis XIV
2
tidak disukai untuk 'yang seharusnya'. Bagaimana jika saya berkata "jika Anda menggunakan React daripada Angular (yang seharusnya Anda lakukan) ..."? Bukan sikap yang harus dimiliki dalam ekosistem ini IMHO.
Valentin Waeselynck
@ValentinWaeselynck Anda benar sekali. Saya mengedit jawaban saya untuk menghilangkan bias saya.
Jordan Skole
1
Bekerja untuk saya! Terima kasih. Saya benar-benar menambahkannya ke fungsi run saya, lalu mengubah $ scope menjadi $ rootScope.
JDavies
2
Seperti yang ditunjukkan oleh Angular University dalam jawaban yang berbeda, $ viewContentLoaded mungkin awalnya tidak ada di sana, tetapi sekarang berfungsi di penyedia ngRoute bawaan, dengan cara yang persis sama. Dengan pemikiran tersebut, saya pikir ini adalah jawaban yang cepat, sederhana, dan dapat dibaca yang akan dicari oleh banyak (kebanyakan?) Pembaca di masa depan.
Kevin Crumley
3

saya mengamati manipulasi DOM sudut dengan JQuery dan saya memang menetapkan penyelesaian untuk aplikasi saya (semacam situasi yang telah ditentukan dan memuaskan yang saya perlukan untuk abstrak aplikasi saya) misalnya saya berharap ng-repeater saya menghasilkan 7 hasil dan di sana untuk saya akan mengatur fungsi observasi dengan bantuan setInterval untuk tujuan ini.

$(document).ready(function(){

  var interval = setInterval(function(){

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

  },50);

});
Hassan Gilak
sumber
3
Saya tidak akan melakukan ini. Menggunakan interval untuk memeriksa hal-hal yang terjadi bukanlah praktik yang baik, tidak dapat diskalakan, dan ada cara lain untuk mewujudkannya. Pengatur waktu adalah untuk melakukan tugas konkret yang perlu dilakukan setelah jangka waktu tertentu, bukan untuk "menebak" saat konten atau hasil sudah siap.
dudewad
Belum lagi bahwa menggunakan timer jquery terhadap platform sudut adalah kontra-produktif- angular memiliki kelas batas waktu dan Anda harus menggunakannya jika tidak, Anda mengangkangi dua kerangka kerja dan itu menjadi membingungkan dengan sangat cepat.
dudewad
3

Jika Anda tidak menggunakan modul ngRoute , misalnya Anda tidak memiliki $ viewContentLoaded acara .

Anda dapat menggunakan metode direktif lain:

    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");
                    }
                );
            }
        };
    }

Sesuai dengan jawaban trusktr itu memiliki prioritas terendah. Ditambah $ timeout akan menyebabkan Angular dijalankan melalui seluruh event loop sebelum eksekusi callback.

$ rootScope digunakan, karena memungkinkan untuk menempatkan direktif dalam lingkup aplikasi apa pun dan hanya memberi tahu pendengar yang diperlukan.

$ rootScope. $ emit akan mengaktifkan peristiwa untuk semua $ rootScope. $ hanya pada pendengar. Bagian yang menarik adalah bahwa $ rootScope. $ Broadcast akan memberi tahu semua $ rootScope. $ Pada serta $ scope. $ Pada Sumber pendengar

Vadim P.
sumber
2

Menurut tim Angular dan masalah Github ini :

kita sekarang memiliki peristiwa $ viewContentLoaded dan $ includeContentLoaded yang masing-masing dipancarkan dalam ng-view dan ng-include. Saya pikir ini sedekat yang bisa diketahui orang ketika kita selesai dengan kompilasi.

Berdasarkan hal ini, tampaknya saat ini hal ini tidak mungkin dilakukan dengan cara yang andal, jika tidak Angular akan menyediakan acara tersebut di luar kotak.

Bootstrap aplikasi menyiratkan menjalankan siklus intisari pada cakupan root, dan juga tidak ada peristiwa siklus intisari yang selesai.

Menurut dokumen desain Angular 2 :

Karena multi digest, tidak mungkin untuk menentukan dan memberi tahu komponen bahwa modelnya stabil. Ini karena notifikasi selanjutnya dapat mengubah data, yang dapat memulai kembali proses pengikatan.

Menurut ini, fakta bahwa ini tidak mungkin adalah salah satu alasan mengapa keputusan diambil untuk menulis ulang di Angular 2.

Universitas Angular
sumber
2

Saya memiliki fragmen yang dimuat-in setelah / oleh sebagian utama yang masuk melalui perutean.

Saya perlu menjalankan fungsi setelah sub-parsial itu dimuat dan saya tidak ingin menulis arahan baru dan menemukan Anda bisa menggunakan cheeky ngIf

Pengontrol parsial induk:

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

HTML subpihak

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

Jika Anda ingin membuat JS dengan data sisi server (JSP, PHP), Anda dapat menambahkan logika Anda ke layanan, yang akan dimuat secara otomatis saat pengontrol Anda dimuat.

Selain itu, jika Anda ingin bereaksi ketika semua arahan selesai dikompilasi / menghubungkan, Anda dapat menambahkan solusi yang diusulkan sesuai di atas dalam logika inisialisasi.

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

    // add your initialization logic here

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


module.controller('YourController', function (YourControllerInitService) {
});
Nikolay Georgiev
sumber
0

Ini semua adalah solusi hebat, Namun, jika Anda saat ini menggunakan Routing maka saya menemukan solusi ini menjadi yang termudah dan paling sedikit kode yang diperlukan. Menggunakan properti 'Resol' untuk menunggu janji diselesaikan sebelum memicu rute. misalnya

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

})

Klik di sini untuk dokumen lengkap - Penghargaan untuk K. Scott Allen

kesurupan
sumber
0

mungkin saya dapat membantu Anda dengan contoh ini

Di fancybox khusus saya menampilkan konten dengan nilai interpolasi.

dalam layanan, dalam metode fancybox "terbuka", saya lakukan

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

$ compile mengembalikan data yang dikompilasi. Anda dapat memeriksa data yang dikompilasi

shailendra pathak
sumber