Monday, May 20, 2024
 Popular · Latest · Hot · Upcoming
171
rated 0 times [  176] [ 5]  / answers: 1 / hits: 21761  / 8 Years ago, tue, may 10, 2016, 12:00:00

Update: I put a bounty on this question. I am not looking for hacks or workarounds. I am looking for an official way to access the dom in an angular component, and an explanation why the behavior I see ($postLink running to early) seems to be contradictory to the official docs.

The official docs state (here):




$postLink() - Called after this controller's element and its children have been linked. Similar to the post-link function this hook can be used to set up DOM event handlers and do direct DOM manipulation




Original question: I have an example of the problem here -> http://plnkr.co/edit/rMm9FOwImFRziNG4o0sg?p=preview



I am using an angular component and I want to modify the dom in the post link function, but it doesn't work, it seems that the function runs too early, before the template is actually ready in the dom after all the angular processing.



In the html page, I have this:



<my-grid grid-id='foo'></my-grid>


The component is defined as:



appModule.component('myGrid',{
controller: gridController,
bindings: {
gridId: <,
},
templateUrl: 'gridTemplate'
});


In the component template I have this:



<table id='{{$ctrl.gridId}}'>
...


(The binding itself works, there is no doubt. Eventually, in the html the id of the table is 'foo' as expected).



In the controller, I have something like this:



function gridController($scope, $compile, $attrs) {
console.log (grid id is: + this.gridId); // 'foo'

this.$postLink = function() {
var elem = document.getElementById(this.gridId);
// do something with elem, but elem is null
}
}


What I see when debugging is that when the $postLink function is executed, the table is in the dom but its id attribute is still {{$ctrl.gridId}} instead of foo, so document.getElementById() finds nothing. This seems in contrast to the documentation.

What am I missing? Is there a different way to access the dom in the component?



Update 2: Today I realized the same problem occurs with the regular link function of directives, it is not limited to components. So apparently I misunderstood the meaning of do direct DOM manipulation - the link function runs on an element that is detached from the dom, so using the document object with selectors is useless.


More From » angularjs

 Answers
43

The documentation regarding $postLink() is correct. It's called after its controller's element and its children have been linked. This doesn't mean that you'll see a directive's result immediately. Maybe it's calling $http and inserting the result once it arrives. Maybe it's registering a watcher which in turns sets the result, as most of Angular's built-in directives do.



The underlying issue in your case is that you want to perform DOM manipulations after the interpolations have been compiled, or better yet, after their registered watcher had had time to run once.



Unfortunately, there isn't an official way to do this. Nevertheless, there are ways of accomplishing this, but you won't find them listed in the documentation.



Two popular ways of running a function after the interpolations have been compiled are:




  • using $timeout without a delay (as it defaults to 0): $timeout(function() { /* Your code goes here */ });


  • using .ready() which is provided by Angular's jqLite




In your case, you're much better off using a watcher to run a function once the element with the given ID exists:



var deregistrationFn = $scope.$watch(() => {
return document.getElementById(this.gridId);
}, (newValue) => {
if (newValue !== null) {
deregistrationFn();

// Your code goes here
}
});


Finally, in my opinion, I believe that whenever you need to wait for the interpolations to be compiled, or for certain directives to insert their value, you're not following the Angular's way of building things. In your case, why not create a new component, myGridTable which requires myGrid as a parent, and add its appropriate logic there. This way, each component's responsibility is much better defined and it's easier to test things.


[#62230] Monday, May 9, 2016, 8 Years  [reply] [flag answer]
Only authorized users can answer the question. Please sign in first, or register a free account.
kaleefridad

Total Points: 399
Total Questions: 97
Total Answers: 114

Location: North Korea
Member since Fri, Nov 4, 2022
2 Years ago
;