angularJS:等待ng-if完成,以确保DOM准备就绪

bas*_*kum 7 javascript dom angularjs

我正在使用ng-if来显示和隐藏元素.当元素出现时,我想调用一个服务,该服务在新元素中滚动到某个孩子(通过Id).问题是,如果我在将元素设置为可见之后尝试立即调用我的服务函数,那么DOM似乎还没有准备就绪.

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

myApp.factory("ScrollService", function () {
    return {
        scroll: function (id) {
            console.log(document.getElementById(id));
        }
    };
});

function MyCtrl($scope, ScrollService) {
    $scope.visible = false;

    $scope.toggleVisibility = function () {
        $scope.visible = !$scope.visible;
        if ($scope.visible) {
            ScrollService.scroll("myId"); //output: null
        }
    };
}
Run Code Online (Sandbox Code Playgroud)

document.getElementById()总会导致null.

这也是一个小提琴,它演示了这个问题:http://jsfiddle.net/Dpuq2/

那么有什么办法可以在ng-if操作之后立即触发一个函数吗?

编辑

使用MinkoGechev的小提琴,我能够在更真实的环境中重现我的错误,并使用指令而不是服务:FIDDLE

问题似乎发生了,因为我ng-repeatng-if-container中使用:

<div ng-controller="MyCtrl">
    <div ng-if="visible"> 
        <div id="myId" data-scroll="itemId">
            <div id="xy"></div>
            <div ng-repeat="item in items" id="{{ item.number }}">{{ item.number }}</div>
        </div>
    </div>
    <button ng-click="toggleVisibility()">toggle</button>
</div>
Run Code Online (Sandbox Code Playgroud)

这是相应的指令加控制器:

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

myApp.directive("scroll", function () {
    return {
        scope: {
            scroll: '='
        },
        link: function (scope) {
            scope.$watch('scroll', function (v) {
                console.log(v, document.getElementById(scope.scroll));
            });
        },
        transclude: true,
        template: "<div ng-transclude></div>"
    };
});

function MyCtrl($scope) {
    $scope.visible = false;
    $scope.itemId = "";
    $scope.items = [];
    for (var i = 1; i < 10; i++) {
        $scope.items.push({
            number: i,
            text: "content " + i
        });
    }

    $scope.toggleVisibility = function () {
        $scope.visible = !$scope.visible;
        if ($scope.visible) {
            $scope.itemId = "3";
        }
    };
}
Run Code Online (Sandbox Code Playgroud)

因此,只要我切换容器的可见性,我就会设置要滚动的元素的Id:

$scope.itemId = "3"
Run Code Online (Sandbox Code Playgroud)

如果我使用1到10之间的数字(由ng-repeat创建的元素的ID),它将失败.如果我使用"xy"(生成ng-repeat元素旁边的一个元素的Id),它就会成功.

Min*_*hev 2

以下是如何使用指令实现您想要的效果:

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

myApp.directive("scroll", function () {
    return {
        scope: {
            scroll: '='
        },
        link: function (scope) {
            scope.$watch('scroll', function (v) {
                //The value is true, so the element is visible
                console.log(v, document.getElementById('myId'));
            });
        }
    };
});

function MyCtrl($scope) {
    $scope.visible = false;

    $scope.toggleVisibility = function () {
        $scope.visible = !$scope.visible;
    };
}
Run Code Online (Sandbox Code Playgroud)

这是演示(打开控制台查看日志)。

注意:AngularJS 强制关注点分离,从而产生更具可读性和可维护性的代码。使用“Angular 方式”时应遵循的规则之一是将所有 DOM 操作放在指令内。