Accessing DOM from within linking function scope.$watch: replace set to true vs false

I need to manipulate the DOM from within my linking function.

I noticed that when i set replace to false, I am able to access the DOM (http://jsfiddle.net/bcsU8/)

//body of directive
return {
    restrict: 'A',
    replace: false,
    scope: {
        bar: '@myDir'
    },
    template: '<div id="{{bar}}">foo bar is <span>{{bar}}</span></div>',
    link: function(scope, element, attr) {
        scope.$watch('myDir', function(value) {
            console.log('In watch - scope.bar: ', scope.bar);
            console.log('DOM accesible? ', $("#"+scope.bar).length == 1);
        });
    }
};

but when I set it to true I can't (http://jsfiddle.net/PpXgb/)

return {
    restrict: 'A',
    replace: true,
    scope: {
        bar: '@myDir'
    },
    template: '<div id="{{bar}}">foo bar is <span>{{bar}}</span></div>',
    link: function(scope, element, attr) {
        scope.$watch('myDir', function(value) {
            console.log('In watch - scope.bar: ', scope.bar);
            console.log('DOM accesible? ', $("#"+scope.bar).length == 1);
        });
    }
};

Why am I not able to access the DOM when replace is on? I have not found anything in the documentation to indicate there should be a difference between these 2 cases.

From the docs on linking function it sounds like the DOM is available after the linking process: (http://docs.angularjs.org/guide/directive)

Post-linking function Executed after the child elements are linked. It is safe to do DOM transformation in the post-linking function.

Please note that in my scope.$watch I'm actually calling a jQuery plugin that expects the DOM to be there, not accessing elements directly via $()

Your issue in this case is that the element is not yet attached to the DOM when the link function is run. This is not really an issue for what you're trying to do; the issue is that you're breaking a best practice by trying to access the element not through the element object passed to the link function, but through a jQuery selector. Try using the element object and I think you'll find your code suddenly works.

But there are caveats to the execution order of directive methods, so there are some cases where this still wouldn't work, but you're not likely to encounter them in a basic directive. Just the same, you should read the guide page on directives to get a better understanding of how AngularJS treats directives.