angularJS:等待模板在指令加载之前进行评估

情况

比方说,我有一个指令,它必须通过ID访问某些元素,在定义指令的元素内部。 可能发生的问题是,在指令被评估时,子元素还没有。 结果是,我无法通过他们的ID访问这些元素。

小提琴

<div ng-controller="MyCtrl">
  <div color="elementId">
      <div ng-repeat="item in items" id="{{ item.id }}">
          {{ item.name }}
      </div>
  </div>
</div>

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

    myApp.directive("color", function () {
        return {
            restrict: "A",   
            link: function (scope, element, attributes) {

                var name = attributes.color,
                    el = element[0];

                scope.$watch(name, function () {
                    var id = scope[name];
                    console.log(id); //id1
                    console.log(element.children().eq(0).attr("id")); //{{ item.id }}
                    element.find("#"+id).css("background-color","red");
                });
            }        
        };
    });

    function MyCtrl($scope) {
        $scope.items = [
            { id:"id1", name:"item1" },
            { id:"id2", name:"item2" }
        ];

        $scope.elementId="id1";
    }

</script>

所以我的指令应该只用$scope.elementId的id来$scope.elementId元素的背景颜色。 (顺便说一句,我知道我可以更简单地处理这个简单的例子,它应该只是说明一般问题)。 问题在于,ng-repeat内的元素的ID尚未出现。 正如代码中的评论所指出的那样,ID仍然是“{{item.id}}”。 所以角度还没有评估这部分。

我现在明显的问题是:我怎么能让我的指令等待后代元素被完全评估?

进一步解释

在我的真实应用程序中,我想要一个指令,使我能够滚动到页面上的某些元素。 我也使用分页指令分割我想要显示的元素。 由于分页,DOM中只有真正可见的元素,所以不可见的元素已经在我的控制器中被滤除了。

我也有一个侧边栏,其中有所有元素的小链接(不仅是可见的)。 当有人点击边栏中的元素时,应该发生两个事件:

  • 跳转到正确的页面
  • 滚动到corrent元素
  • 当我跳转到页面时,我基本上已经遇到了上述情况。 我有一个全新的元素列表,必须由ng-repeat处理。 但直接在那之后,我试着告诉我的scroll-directive,它应该滚动ID为“xy”的元素,但是这个ID尚未分配。


    使用$ timeout包装您的$ scope.elementId =“Id1”以通知角度来调用监听器。 (这也可以用$ scope。$ apply()来完成,但是这会导致另一个问题)

    这里是jsfiddle链接

    代码是 -

        var myApp = angular.module('myApp',[]);
    
        myApp.directive("color", ['$timeout',  function ($timeout) {
            return {
                restrict: "A",   
                link: function (scope, element, attributes) {
                    console.log(element)
                    var name = attributes.color,
                        el = element[0];
    
                     scope.$watch(name, function () {
                         var id = scope[name];
                         console.log(id); //id1
                         console.log(element.find("#"+id)); //{{ item.id }}
                         element.find("#"+id).css("background-color","red");
                     });
                }        
            };
        }]);
    
    myApp.controller("MyCtrl", function($scope, $timeout) {
        $scope.items = [
            { id:"id1", name:"item1" },
            { id:"id2", name:"item2" }
        ];
    
        $timeout(function() {
            $scope.elementId="id1";
        });
    });
    

    如果最终编写了一个getElementById帮助器函数,该函数返回一个承诺并且有一个内部时间间隔,如果该元素存在或不存在,则每隔100ms检查一次:

    更新的小提琴

    function getElementById(elementId) {
        var deferred = $q.defer(),
            intervalKey,
            counter = 0, 
            maxIterations = 50;
    
        intervalKey = setInterval(function () {
            var element = document.getElementById(elementId);
            if (element) {
                deferred.resolve(element);
                clearInterval(intervalKey);
            } else if (counter >= maxIterations) {
                deferred.reject("no element found");
                clearInterval(intervalKey);
            }
            counter++;
        }, 100);
    
        return deferred.promise;
    }
    

    在我举的例子中,我会像这样使用它:

    getElementById(id).then(function (element) {
        $(element).css("background-color","red");
    }, function (message) {
        console.log(message);
    });
    

    这仍然不是我的首选解决方案,但它现在起作用并解决了我的问题。 但我仍然好奇,如果有更好的方法来解决这个问题的话。


    根据Jim Hoskins的文章,以下代码段可以帮助你。

      scope.$watch(name, function () {
        setTimeout(function () {
          scope.$apply(function () {
            var id = scope[name];
            console.log(id); //id1
            console.log(element.find("#"+id)); //{{ item.id }}
            element.find("#"+id).css("background-color","red");
          }  
        }, 200))
      });
    

    发布这个答案可以帮助人们节省一些时间(当然,阅读完整的文章很有帮助)

    链接地址: http://www.djcxy.com/p/95229.html

    上一篇: angularJS: wait for template to be evaluated before directive loads

    下一篇: How to apply row virtualization for a table / list in HTML/CSS/JS?