2013-11-03 46 views
7

我正在使用ng-if來顯示和隱藏元素。當元素出現時,我想調用一個服務,該服務在新元素內滾動到某個孩子(由Id)。問題是,如果在將元素設置爲可見之後嘗試調用我的服務函數,那麼DOM似乎還沒有準備好。angularJS:等待ng - 如果完成,確保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()總是會導致null

這裏也是一個小提琴,演示該問題:http://jsfiddle.net/Dpuq2/

那麼,有沒有辦法,儘快的DOM是NG-如果被操縱後準備觸發功能?

編輯

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

這裏是根據指令加續輥:

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

所以只要我切換我的容器,我設置元素的ID,而我想要滾動的可見性:

$scope.itemId = "3" 

如果我使用從1到10的數字之一(由ng-repeat創建的元素的ID)它將失敗。如果我使用「xy」(位於ng-repeat元素旁邊的一個元素的Id),它會成功。

+3

請,不實現DOM到控制器,使用指令代替 –

+0

@MaximShoustin我沒不是將它實現成一個控制器,而是實現一個服務,我也嘗試使用一個指令,結果相同 – basilikum

+0

@basilikum在一個指令的link()函數中,你確定鏈接元素的DOM這個指令已經準備就緒,那就是在這裏,你必須將元素滾動到他的孩子。 – Blackhole

回答

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

這裏是DEMO(打開你的控制檯查看日誌)。

注意:AngularJS強制分離關注點,從而導致更多的可讀和可維護代碼。在使用「Angular方式」時應遵循的規則之一是將所有DOM操作僅限指令內。

+0

謝謝你的回答,我看到你的小提琴奏效。不幸的是,當我將其應用到我的應用中時,它不再起作用。也許還有其他事情正在發生。我將在稍後再回應。 – basilikum

+1

我剛編輯我的問題。看來,這個錯誤與使用ng-repeat有關。你有什麼想法,我做錯了什麼? – basilikum

1

您是否找到了解決問題的方法?

由於您提到這個問題似乎與ng-repeat有關,您是否嘗試過「scope。$ last?」?

我絕不是一個有經驗的網頁開發人員,但我遇到類似的問題,工具提示不會在ng-repeat「生成」的項目上顯示,並讓它使用應用工具提示的指令「範圍。$最後的」

舉個例子:

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

也許更有經驗的人可以給一些更多的輸入