簡體   English   中英

如何在准備好文檔的AngularJS控制器中運行函數?

[英]How to run function in AngularJS controller on document ready?

我在我的角度控制器中有一個函數,我希望可以在准備好文檔的文件上運行此函數,但是我注意到在創建dom時,它會運行角度函數。

 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
 }

有人知道我該怎么做嗎?

我們可以使用angular.element(document).ready()方法為文檔准備就緒時附加回調。 我們可以像這樣簡單地將回調附加到控制器中:

angular.module('MyApp', [])

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

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

看到這篇文章如何在頁面加載時執行角度控制器功能?
快速查找:

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

這樣,您不必等到文檔准備就緒。

如果那時document.readyState設置為“ complete”,則Angular將在DOMContentLoaded事件或評估angular.js腳本時自動初始化。 此時,Angular尋找ng-app指令,該指令指定您的應用程序根目錄。

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

這意味着控制器代碼將在DOM准備就緒后運行。

因此,這只是$scope.init()

Angular有幾個時間點開始執行功能。 如果您尋找類似jQuery的東西

$(document).ready();

您可能會發現此模擬角度非常有用:

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

當您要操作DOM元素時,這一功能非常有用。 僅在加載所有te元素后才開始執行。

UPD:當您要更改CSS屬性時,以上所述適用。 但是,有時在您想要測量元素屬性(例如寬度,高度等)時不起作用。在這種情況下,您可能需要嘗試以下操作:

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

我有類似的情況,在加載視圖之后,以及加載,初始化視圖中的特定第3方組件並將其自身的引用放在$ scope上之后,我需要執行控制器功能。 最終對我有用的是在此scope屬性上設置一個watch,並且僅在函數初始化后才觸發它。

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

多次使用未定義的值調用監視程序。 然后,當創建網格並具有預期的屬性時,可以安全地調用初始化函數。 第一次使用未定義的newValue調用監視程序時,oldValue仍將是未定義的。

這是我在使用coffeescript的外部控制器內部的嘗試。 效果不錯。 請注意,settings.screen.xs | sm | md | lg是我在應用程序附帶的非丑化文件中定義的靜態值。 這些值是針對同義媒體查詢大小的每個Bootstrap 3官方斷點:

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

答案

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

是我測試過的大多數方案中唯一可行的方案。 在具有4個組件的示例頁面中,所有這些組件均通過模板構建HTML,事件的順序為

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

因此,在大多數情況下,$ document.ready()毫無用處,因為以角度構造的DOM可能還差得遠。

但是更有趣的是,即使在$ viewContentLoaded被觸發后,仍然找不到感興趣的元素。

僅在執行$ timeout之后才找到它。 請注意,即使$ timeout的值為0,執行前也要經過近200毫秒,這表明該線程被擱置了一段時間,大概是在DOM的主線程上添加了角度模板的情況下。 從第一個$ document.ready()到最后一個$ timeout執行的總時間接近500毫秒。

在一種特殊情況下,設置了組件的值,然后在$ timeout中稍后更改了text()值,則必須增加$ timeout值,直到它起作用為止(即使可以在$ timeout期間找到該元素) )。 在第3方組件中發生異步操作導致值優先於文本,直到經過足夠的時間為止。 另一個可能是$ scope。$ evalAsync,但是沒有嘗試過。

我仍在尋找一個事件,該事件告訴我DOM已經完全解決,可以對其進行操作,以便所有情況都可以進行。 到目前為止,必須有一個任意的超時值,這意味着充其量只是在慢速瀏覽器上可能無法正常工作。 我還沒有嘗試過諸如liveQuery和發布/訂閱之類的JQuery選項,這些選項可能有效,但肯定不是純角度的。

如果您收到類似getElementById call returns null ,則getElementById call returns null ,這可能是因為該函數正在運行,但是ID沒有時間將其加載到DOM中。

嘗試延遲使用威爾的答案(朝上)。 例:

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

為什么不嘗試使用什么角度文檔提到的https://docs.angularjs.org/api/ng/function/angular.element

angular.element(回調)

我在$ onInit(){...}函數中使用了此函數。

 var self = this;

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

這對我有用。

$scope.$on('$ViewData', function(event) {
//Your code.
});

暫無
暫無

聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.

 
粵ICP備18138465號  © 2020-2024 STACKOOM.COM