AngularJS: Wait ng - if done, to make sure the DOM is ready

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"); //output: null } }; } 

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.

+7
javascript dom angularjs
source share
2 answers

Here's how you can achieve the effect you are 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 console to view logs).

NOTE : AngularJS reinforces the separation of concerns, which leads to much more readable and maintainable code. One of the rules you should follow when using the "Angular method" is to include all DOM directives ONLY inside the directives.

+2
source share

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

I am by no means an experienced web developer, but I had a similar problem when the tooltip didn’t show on the elements “ng-repeat” generated and made it work with a directive that applied the tooltip using the “sphere. $ Last”

As an example:

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

Perhaps someone with more experience can provide more information.

+1
source share

All Articles