AngularJs подія для виклику після завантаження вмісту


163

У мене є функція, яку я хочу зателефонувати після завантаження вмісту сторінки. Я читав про $ viewContentLoaded, і це не працює для мене. Я шукаю щось подібне

document.addEventListener('DOMContentLoaded', function () { 
     //Content goes here 
}, false);

Наведений вище виклик не працює для мене в контролері AngularJs.


1
Це добре працює stackoverflow.com/q/14968690/6521116
Kris Roofe

Відповіді:


163

Згідно з документацією $ viewContentLoaded , вона повинна працювати

Випускається щоразу, коли вміст ngView перезавантажується.

$viewContentLoaded подія випромінюється, що означає, щоб отримати цю подію, вам потрібен батьківський контролер, як

<div ng-controller="MainCtrl">
  <div ng-view></div>
</div>

Від MainCtrlвас можна послухати подію

  $scope.$on('$viewContentLoaded', function(){
    //Here your view content is fully loaded !!
  });

Перевірте демонстрацію


59
Проблема такого підходу полягає в тому, що контролери не повністю ініціалізовані на даний момент.
Попелясто-блакитний

12
@Reza Він правильний, ця подія запускається, коли додається dom, але перед тим, як кутова закінчила обробку купола. Ви можете перевірити це, додавши ідентифікатор або клас у вигляді кутової змінної і спробувати знайти його в $ viewContentLoaded з jQuery. Ви його не знайдете.
Thomas Kekeisen

1
@Reza так, Томас має рацію, що елемент форми не може отримати доступ до $ viewContentLoaded say, $ range.formName.elementName. $ SetValidity ("validateRule", false); викине "TypeError: Неможливо прочитати властивість 'elementName' undefined"
Mussammil

2
Те саме можна назвати на рівні $ rootScope. . Замість $ $ на сферу, вона повинна бути $ rootScope $ на і всередині app.run () блоку.
Vil

4
Ця опція не буде працювати, якщо у вас є ng-repeatкілька вкладених директив, які генерують HTML / вміст на основі складних циклів і умов. Відображення триває деякий час, навіть після початку $viewContentLoadedподії. Як ви можете переконатися, що всі елементи були повністю виведені, а потім виконати певний код? Будь-які відгуки?
tarekahf

104

Кутовий <1.6.X

angular.element(document).ready(function () {
    console.log('page loading completed');
});

Кутова> = 1.6.X

angular.element(function () {
    console.log('page loading completed');
});

Це стосується app.js?
zcoon

3
ви можете послухати його у своїх controllers.js
hariszaman

2
Працює нормально і в головному файлі app.js.
Loubot

Ця відповідь працює для мене! Просто дивіться, що на сторінці елемента документації 'ready () (застаріло, використовуйте angular.element (зворотний виклик) замість angular.element (документ). Вже (зворотний виклик))'
Lovera

Це працювало для мене. Прийнятий підхід відповіді не працює всередині контролера.
Фабіано

76

фіксовано - 2015.06.09

Використовуйте директиву та readyметод кутових елементів так:

js

.directive( 'elemReady', function( $parse ) {
   return {
       restrict: 'A',
       link: function( $scope, elem, attrs ) {    
          elem.ready(function(){
            $scope.$apply(function(){
                var func = $parse(attrs.elemReady);
                func($scope);
            })
          })
       }
    }
})

html

<div elem-ready="someMethod()"></div>

або для тих, хто використовує контролер як синтаксис ...

<div elem-ready="vm.someMethod()"></div>

Перевага цього полягає в тому, що ви можете бути настільки широкими або деталізованими з вашого інтерфейсу, скільки вам подобається, і ви виймаєте логіку DOM зі своїх контролерів. Я б заперечив, що це рекомендований кутовий спосіб.

Вам може знадобитися визначити пріоритет цієї директиви, якщо у вас є інші директиви, що працюють на тому ж вузлі.


це виглядає як дуже гарне рішення, але я не міг змусити його працювати. він задихнувся від elem.ready( $scope.$apply( readyFunc( $scope ))); будь-яких ідей, чому це може бути? Можливо, відбулось оновлення до кутового? У будь-якому випадку - це елегантний підхід, якщо це може спрацювати.
domoarigato

1
нм, я бачу, в чому проблема. Була помилка друку на attrs.onReady, має бути такою, якою вона є зараз. Інша проблема полягала в тому, що я називав це фанкі ... ... що я отримую за перетворення кофеескрипту з пам'яті в JS.
jusopi

1
Я думаю, що в певних випадках це може бути добре, але мої аргументи проти цього: я думаю, що очікування його коду при простому погляді на те, що це поверне деяке значення тексту для відображення в DOM, ерго, це вимагає уважного огляду; Це не дозволяє проводити будь-які терміни з точки зору пріоритетності директиви, ви застрягли на рівні контролера, якщо не використовуєте $timeout; Ви явно створюєте додаток. Вузол DOM просто виконувати логіку без дому; Це може бути повторно використане лише в тому випадку, якщо цей метод знаходиться далеко в ієрархії діапазону $ таким чином, щоб дітям сфери успадковували його; я просто думаю, що це виглядає погано з точки зору НГ;
дзюсопі

5
Працював для мене після додавання $timeout(function() {})навколо elem.ready(). Інакше це було $digest already in progressпомилкою. Але все одно, спасибі тонну! Я боровся з цим протягом останньої години.
rkrishnan

1
Копання по області $ здається порожнім. Будь-які ідеї?
MiloTheGreat

66

Ви можете безпосередньо зателефонувати йому, додавши {{YourFunction()}}після елемента HTML.

Ось Plunker Link.


6
Чи можете ви детальніше розглянути свою відповідь, додавши трохи більше опису про рішення, яке ви надаєте?
аборисон

Я думаю, ви хочете викликати функцію, коли цей html елемент завантажений. Тому називайте цю функцію, як згадувалося вище. Якщо я гадаю, що ви сумніваєтесь, тоді це спрацює інакше, будь ласка, розробіть своє запитання. :)
синій

14
При виклику такої функції. Переконайтесь, що його виклик один раз або інакше цикл дайджесту буде працювати нескінченно, і з’являється помилка
Ашан

2
мені подобається це рішення, воно дійсно таке просте
Kamuran Sönecek

1
Це фантастично - лише одна проблема. Здається, що моя функція працює 5 разів, коли я цим користуюся. Я додав лічильник, щоб він працював нормально, але мені просто цікаво, чи хтось знає, чому це станеться ... Здається, це трохи дивно ви знаєте?
itchyspacesuit

22

Мені довелося реалізувати цю логіку під час роботи з google-діаграмами. Що я зробив, це те, що наприкінці мого html всередині визначення контролера я додав.

  <body>
         -- some html here -- 
--and at the end or where ever you want --
          <div ng-init="FunCall()"></div>
    </body>

і в цій функції просто викликайте свою логіку.

$scope.FunCall = function () {
        alert("Called");
}

Я використовував це, але вгорі сторінки init вимагав завантаження діва вже так, переміщуючи ng-init в нижню частину сторінки, виправлено мою проблему, приємна підказка і це має сенс.
Гурнард

Єдина відповідь, яка допомогла мені у вирішенні моєї проблеми (jquery mobile порожній вибір)
kaiser

Це справжня відповідь, оскільки він адаптується до динамічно завантажених елементів керування і надзвичайно простий у виконанні.
Джейсон Себрінг

ця відповідь заощадила мені деякий час, такий елегантний та ефективний для мого випадку використання
Sello

4
var myM = angular.module('data-module');

myM.directive('myDirect',['$document', function( $document ){

    function link( scope , element , attrs ){

        element.ready( function(){

        } );

        scope.$on( '$viewContentLoaded' , function(){

            console.log(" ===> Called on View Load ") ;

        } );

    }

    return {
        link: link
    };

}] );

Вищеописаний метод працював на мене


3

ви можете зателефонувати у версію JavaScript для події завантаження у кутовому js. ця подія ng-load може бути застосована до будь-якого елемента dom, наприклад div, span, body, iframe, img тощо.

завантажити ng-load для кутових js

Далі наводиться приклад для iframe, як тільки він завантажується testCallbackFunction, буде викликано в контролер

ПРИКЛАД

JS

    // include the `ngLoad` module
    var app = angular.module('myApp', ['ngLoad']);
    app.controller('myCtrl', function($scope) {
        $scope.testCallbackFunction = function() {
          //TODO : Things to do once Element is loaded
        };

    });  

HTML

  <div ng-app='myApp' ng-controller='myCtrl'> 
      <iframe src="test.html" ng-load callback="testCallbackFunction()">  
  </div>

Будь ласка, додайте приклад коду, щоб показати, як ОП може вирішити проблему
jro

@jro Оновлено мої анс. Сподіваюся, це буде корисним :)
Даршан Джайн

2

Якщо ви отримуєте дайджест $, який вже триває помилка, це може допомогти:

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

                if(!$scope.$$phase) {
                    $scope.$apply(function(){
                        var func = $parse(attrs.elemReady);
                        func($scope);
                    })
                }
                else {

                    var func = $parse(attrs.elemReady);
                    func($scope);
                }

            })
        }
    }

0

Запуск після завантаження сторінки повинен бути частково задоволений, встановивши слухача події для події завантаження вікна

window.addEventListener("load",function()...)

Всередині module.run(function()...)кута ви матимете повний доступ до структури модуля та залежностей.

Можна broadcastі emitподії для мостів зв'язку.

Наприклад:

  • модуль встановити подію на завантаження та побудувати логіку
  • модуль передає подію контролерам, коли цього вимагає логіка
  • контролери будуть слухати та виконувати власну логіку на основі процесів завантаження модулів.

0

Я використовував {{myFunction()}}у шаблоні, але потім знайшов інший спосіб тут, використовуючи $timeoutвсередині контролера. Думав, що я поділюсь цим, чудово працює для мене.

angular.module('myApp').controller('myCtrl', ['$timeout',
function($timeout) {
var self = this;

self.controllerFunction = function () { alert('controller function');}

$timeout(function () {
    var vanillaFunction = function () { alert('vanilla function'); }();
    self.controllerFunction();
});

}]);

Я спробував усі відповіді тут і чомусь $ timeout - це єдине, що працювало на мене. Не впевнений чому, але це може мати щось спільне з ng-include та термінами ініціювання послуг.
Дрелгор

Я додав плюс до {{myFunction ()}}
спільного спікету

0

Якщо ви хочете, щоб певний елемент повністю завантажився, використовуйте ng-init для цього елемента.

напр <div class="modal fade" id="modalFacultyInfo" role="dialog" ng-init="initModalFacultyInfo()"> ..</div>

функція initModalFacultyInfo () повинна існувати в контролері.


0

Я виявив, що якщо ви вклали представлення - $ viewContentLoaded запускається для кожного з вкладених представлень. Я створив це рішення, щоб знайти остаточний $ viewContentLoaded. Здається, добре працює для встановлення $ window.prerenderReady, як того вимагає Prerender (переходить у .run () в головному app.js):

// Trigger $window.prerenderReady once page is stable
// Note that since we have nested views - $viewContentLoaded is fired multiple
// times and we need to go around this problem
var viewContentLoads = 0;
var checkReady = function(previousContentLoads) {
  var currentContentLoads = Number(viewContentLoads) + 0; // Create a local copy of the number of loads
  if (previousContentLoads === currentContentLoads) { // Check if we are in a steady state
    $window.prerenderReady = true; // Raise the flag saying we are ready
  } else {
    if ($window.prerenderReady || currentContentLoads > 20) return; // Runaway check
    $timeout(function() {checkReady(currentContentLoads);}, 100); // Wait 100ms and recheck
  }
};
$rootScope.$on('$stateChangeSuccess', function() {
  checkReady(-1); // Changed the state - ready to listen for end of render
});
$rootScope.$on('$viewContentLoaded', function() {
  viewContentLoads ++;
});

0
var myTestApp = angular.module("myTestApp", []); 
myTestApp.controller("myTestController", function($scope, $window) {
$window.onload = function() {
 alert("is called on page load.");
};
});

Хоча цей код може відповісти на питання, надаючи додатковий контекст стосовно того, чому та / або як цей код відповідає на питання, покращує його довгострокове значення.
rollstuhlfahrer

0

Рішення, яке працює для мене, полягає в наступному

app.directive('onFinishRender', ['$timeout', '$parse', function ($timeout, $parse) {
    return {
        restrict: 'A',
        link: function (scope, element, attr) {
            if (scope.$last === true) {
                $timeout(function () {
                    scope.$emit('ngRepeatFinished');
                    if (!!attr.onFinishRender) {
                        $parse(attr.onFinishRender)(scope);
                    }
                });
            }

            if (!!attr.onStartRender) {
                if (scope.$first === true) {
                    $timeout(function () {
                        scope.$emit('ngRepeatStarted');
                        if (!!attr.onStartRender) {
                            $parse(attr.onStartRender)(scope);
                        }
                    });
                }
            }
        }
    }
}]);

Код контролера наступний

$scope.crearTooltip = function () {
     $('[data-toggle="popover"]').popover();
}

Html-код наступний

<tr ng-repeat="item in $data" on-finish-render="crearTooltip()">

-31

Я використовую setIntervalдля очікування завантаження вмісту. Я сподіваюся, що це може допомогти вам вирішити цю проблему.

var $audio = $('#audio');
var src = $audio.attr('src');
var a;
a = window.setInterval(function(){
    src = $audio.attr('src');
    if(src != undefined){
        window.clearInterval(a);
        $('audio').mediaelementplayer({
            audioWidth: '100%'
        });
    }
}, 0);

13
Чи все-таки люди рекомендують setIntervalяк рішення у 2016 році ?
Захарій Дахан

але немає простого api в кутовому ... як .. як це зробити?
Пьотр Кула
Використовуючи наш веб-сайт, ви визнаєте, що прочитали та зрозуміли наші Політику щодо файлів cookie та Політику конфіденційності.
Licensed under cc by-sa 3.0 with attribution required.