为什么我不能访问Angular创建的新DOM元素?

时间:2015-02-09 23:05:58

标签: javascript jquery angularjs

HTML:

<div class="list-group link-list" ng-show="linksForPerson">
    <a href="" class="list-group-item" ng-repeat="link in linksForPerson" ng-click="showLinkDetail(link)" ng-class="{active: isSelectedLink(link)}">
        <h4 class="list-group-item-heading">[[ link.engine.name ]]</h4>
        <p class="list-group-item-text">[[ link.engine.base_url ]]</p>
        <p class="list-group-item-text" ng-show="link.user_sync_id">[[ link.user_sync_id ]]</p>
        <p class="list-group-item-text" ng-show="link.group_sync_id">[[ link.group_sync_id ]]</p>
    </a>
    <a href="" class="list-group-item" ng-click="addLink($event)"><span class="glyphicon glyphicon-plus"></span> Add a new link</a>
</div>

控制器:

appModuleLightDashboard.controller('ManageLinksController',
    function($scope, $http, $timeout) {
        $scope.addLink = function(event) {
            $scope.linksForPerson.push({});

            // Error: [$rootScope:inprog] http://errors.angularjs.org/1.3.0-rc.1/$rootScope/inprog?p0=%24apply
            $('.link-list .list-group-item').eq(-2).trigger('click');

            // But this works ---- why?
            // $timeout( function(){$('.link-list .list-group-item').eq(-2).trigger('click')} , 0);
        }
    });
  • 我已将插值符号更改为[[]],因为它与Django
  • 冲突

问题:

当用户点击&#34;添加新链接&#34;时,将创建一个新的列表项。我想自动选择这个新的列表项。

但看起来我无法选择由Angular创建的新DOM元素(即$('.link-list .list-group-item')不会返回新的元素),除非我用$ timeout包装代码。谁知道为什么?

另外,请告知是否有更多的Angular方法来实现它:)

2 个答案:

答案 0 :(得分:3)

你的问题是&#34;为什么&#34;。答案是因为目前您正在尝试使用jQuery来查找元素,因此尚未将其添加到DOM中。在摘要周期运行之前,这种情况不会发生。

$ timeout有效,因为函数调用现在推迟到下一个摘要周期之后。该解决方案的问题在于,在某些情况下,DOM仍然尚未被修改。

更详细地说,这将有几种失败模式。您正在显示的错误是因为您实际上是在已添加的倒数第二个元素中触发了一个点击,而您正在从摘要周期内执行此操作。如果您已经在集合中添加了两个或更多项目,则会触发角度点击倒数第二个(这恰好不是您认为的那个),这假定它在摘要之外被调用循环并调用$ apply,由于它实际上在摘要周期内,因此失败并显示错误。

&#34;棱角分明的方式&#34;实现你想要的是使用指令。

.directive('triggerClick', function($parse) {
   return {
      restrict: 'A',
      link: function(scope, elem, attr) {
          var fn = $parse(attr['triggerClick']);
          if(scope.$last) {  //or some other logic
             fn(scope);
          }
      }
   }
})

div class="list-group link-list" ng-show="linksForPerson">
    <a href="" class="list-group-item" ng-repeat="link in linksForPerson" ng-click="showLinkDetail(link)" ng-class="{active: isSelectedLink(link)}" trigger-click="showLinkDetail(link)">
        <h4 class="list-group-item-heading">[[ link.engine.name ]]</h4>
        <p class="list-group-item-text">[[ link.engine.base_url ]]</p>
        <p class="list-group-item-text" ng-show="link.user_sync_id">[[ link.user_sync_id ]]</p>
        <p class="list-group-item-text" ng-show="link.group_sync_id">[[ link.group_sync_id ]]</p>
    </a>
    <a href="" class="list-group-item" ng-click="addLink($event)"><span class="glyphicon glyphicon-plus"></span> Add a new link</a>
</div>

这是有效的,因为在构造节点并将其添加到DOM之后,将调用该指令的链接功能。注意添加&#34;触发 - 点击&#34;你的ng-repeat元素。

指令中的元素是一个围绕ng-repeat项目实例的jQuery对象。 Angular将为指令的每个实例调用链接函数,在这种情况下,它是ng-repeat的每个实例。

更多&#34;棱角分明&#34;根本就是不使用点击事件。您没有包含showLinkDetail的实现,而是触发点击,只需在您的控制器中调用它。

作为一般&#34;棱角分明&#34;规则,任何看起来像jQuery的东西都应该只发生在一个指令中。

编辑:有了你需要的更多信息,你可以做到这一点,而不需要做任何DOM操作(没有指令)。

appModuleLightDashboard.controller('ManageLinksController',
    function($scope, $http, $timeout) {
        $scope.activeLink = undefined;

        $scope.addLink = function(event) {
            $scope.activeLink = {};
            $scope.linksForPerson.push($scope.activeLink);
        }

        $scope.showLinkDetail = function(link){
            $scope.activeLink = link
        }

        $scope.isSelectedLink = function(link){
            return $scope.activeLink === link;
        }

    });

<div class="list-group link-list" ng-show="linksForPerson">
    <a href="" class="list-group-item" ng-repeat="link in linksForPerson" ng-click="showLinkDetail(link)" ng-class="{active: isSelectedLink(link)}">
        <h4 class="list-group-item-heading">[[ link.engine.name ]]</h4>
        <p class="list-group-item-text">[[ link.engine.base_url ]]</p>
        <p class="list-group-item-text" ng-show="link.user_sync_id">[[ link.user_sync_id ]]</p>
        <p class="list-group-item-text" ng-show="link.group_sync_id">[[ link.group_sync_id ]]</p>
    </a>
    <a href="" class="list-group-item" ng-click="addLink($event)"><span class="glyphicon glyphicon-plus"></span> Add a new link</a>
</div>

答案 1 :(得分:0)

  1. 您不应该使用ngShow将“添加新链接”放在div中,因为当linksForPerson数组为空时,您将无法添加新链接。此外,将它放在div之外将减轻所有其他操作(基于你想要实现的目标“

  2. linksForPerson是一个数组,请改用<{1}}

  3. 您应该在推送任何数据之前对其进行初始化ng-show="linksForPerson.length"

  4. 使用$scope.linksForPerson=[]是{{}}或[[]]的更好替代方式

  5. 我重构了你的代码。

    ng-bind

    和html(注意使用ng-bind)

    //  ---- controller
    appModuleLightDashboard.controller('ManageLinksController',
    function($scope, $http, $timeout) {
    
        var activeLink;
    
        // you should initiate your array
        $scope.linksForPerson = [];
    
        $scope.isSelectedLink  = function (link) {
            return activeLink === link; 
        };
    
        $scope.addLink = function(event) {
            activeLink = {
                engine: {
                    name : "engine" + ($scope.linksForPerson.length + 1),
                    base_url : " someUrl"
                }
            };
            $scope.linksForPerson.push(activeLink);
        };
    });
    

    这里有jsfiddle供你玩