I use ng-if to show and hide an element. When an element appears, I want to call a service that scrolls a new element to a specific child element (by identifier). The problem is that if I try to call my utility function immediately after the element becomes visible, the DOM is not ready yet.
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");
document.getElementById() will always be null .
Here is also a fiddle that demonstrates the problem: http://jsfiddle.net/Dpuq2/
So, is there a way to run the function as soon as the DOM is ready after manipulating ng-if?
EDIT
Using the MinkoGechev fiddle, I was able to reproduce my error in a more realistic environment and using the directive instead of the service: FIDDLE
The problem arises because I use ng-repeat inside the ng-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>
Here is the corresponding 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 switch the visibility of my container, I set the identifier of the element to which I want to scroll:
$scope.itemId = "3"
If I use one of the numbers from 1 to 10 (Identifiers of the elements created by ng-repeat), it will not work. If I use "xy" (the identifier of the one element that lives next to the ng-repeat elements), it succeeds.