简体   繁体   English

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

[英]angularJS: Wait for ng-if to finish, to make sure that the DOM is ready

I'm using ng-if to show and hide an element. 我正在使用ng-if来显示和隐藏元素。 When the element shows up, I want to call a service, that scrolls within the new element to a certain child (by Id). 当元素出现时,我想调用一个服务,该服务在新元素中滚动到某个孩子(通过Id)。 The problem is, that if I try to call my service function right after setting the element to visible, the DOM doesn't seem to be ready yet. 问题是,如果我在将元素设置为可见之后尝试立即调用我的服务函数,那么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
        }
    };
}

document.getElementById() will always result in null . document.getElementById()将始终为null

Here is also a fiddle, that demonstrates the problem: http://jsfiddle.net/Dpuq2/ 这也是一个小提琴,它演示了这个问题: http//jsfiddle.net/Dpuq2/

So is there any way, to trigger a function as soon as the DOM is ready after being manipulated by ng-if? 那么有什么办法可以在ng-if操作之后立即触发一个函数吗?

EDIT 编辑

Using the fiddle of MinkoGechev, I was able to reproduce my error in a more realistic environment and with using a directive instead of a service: FIDDLE 使用MinkoGechev的小提琴,我能够在更真实的环境中重现我的错误,并使用指令而不是服务: FIDDLE

The problem seems to occur, because I'm using ng-repeat inside of the ng-if -container: 问题似乎发生了,因为我在ng-if -container中使用ng-repeat

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

Here is the according directive plus controller: 这是相应的指令加控制器:

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

So as soon as I toggle the visibility of my container, I'm setting the Id of the element, to which I want to scroll: 因此,只要我切换容器的可见性,我就会设置要滚动的元素的Id:

$scope.itemId = "3"

If I'm using one of the numbers from 1 to 10 (the Ids of the elements created by ng-repeat) it will fail. 如果我使用1到10之间的数字(由ng-repeat创建的元素的ID),它将失败。 If I'm using "xy" (the Id of one element that lives next to the ng-repeat elements) it succeeds. 如果我使用“xy”(生成ng-repeat元素旁边的一个元素的Id),它就会成功。

Here is how you can achieve the effect you're looking for with directives: 以下是如何通过指令实现您正在寻找的效果:

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

Here is DEMO (open your console to see the logs). 这是DEMO (打开控制台查看日志)。

NOTE : AngularJS force separation of concerns which leads to far more readable and maintainable code. 注意 :AngularJS强制分离关注点,从而导致代码更具可读性和可维护性。 One of the rules which you should follow while using "the Angular way" is to put all DOM manipulations ONLY inside directives. 使用“Angular方式”时应遵循的规则之一是将所有DOM操作放在指令中。

Have you found a solution to your problem? 您找到了解决问题的方法吗?

Since you mention that the problem seems to be related to ng-repeat, have you tried "scope.$last?" 既然你提到问题似乎与ng-repeat有关,你试过“范围。$ last?”

I am by no means an experienced web developer, but I have had a similar issue where a tooltip won't show on items "generated" by an ng-repeat and got it working with a directive that applied the tooltip using "scope.$last" 我绝不是一位经验丰富的Web开发人员,但我遇到过类似的问题,工具提示不会显示在ng-repeat“生成”的项目上,而是让它使用了一个使用“scope”来应用工具提示的指令。持续”

As an example: 举个例子:

AppName.directive('directiveName', function () {
    return function (scope, element, attrs) {
        if (scope.$last) {
            <-- Your code here -->
        }
    };
});

Maybe someone with more experience could give some more input. 也许有经验的人可以提供更多的投入。

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM