12

Here is the idea:

So I am trying to use an external library function to create some manipulation in the DOM in one of my controllers that my ng-repeat is connected to.

Newest jsFiddle working but ...

http://jsfiddle.net/GeorgiAngelov/KRbdL/150/

So basically I got it to work with @BrandonTilley's help but I am trying to avoid using $timeout as I don't think that it is a viable solution but a hack.

New fiddle with the help of @BrandonTilley

added onload listener and also I am trying to get the new element or its parent by getElementById but all it returns is NULL.

http://jsfiddle.net/GeorgiAngelov/KRbdL/143/

The problem is the following: I am calling that external function in my controller that adds elements to the ng-repeat array , which in term adds the new elements to the DOM. However, when I am inside the controller, the element does not exist yet, even though I have added it to the array.

How can I bound an external function to be called once the element has actually been appended to the DOM, rather than when it was actually added to the array that controls the ng-repeat?

The problem comes is that I have template 1 calling template 2, then template 2 calls template3 and then template3 calls back template 2, and I want to connect an element from template3 into template2 once template3's finishes rendering template2.

I created a directive that is linked to template3 and I used the $last property but it is still not working because template3 loads but I do not know when template2 finishes loading.Furthermore, the element.ready() does not even fire up. I also tried hacking it around with $timeout and removing element.ready, but it still gave me the error that the child element did not exist yet. I do not want to use $timeout and so I am looking for a more functional solution to my problem.

Also, I tried calling the jsPlumb library when I call the function to create a new firstlevel element but it gives parentNode undefined. I commented it out in addChild function .

Directive that is used in template 3 on the ng-repeat ng-include=template2

app.directive('vectorDrawDirective', function($timeout) {
    return function($scope, element, attrs) {
        //angular.element(element).css('color','blue');
        if ($scope.$last === true) {
            element.ready(function() {
            jsPlumb.connect({
                    source: $scope.firstlevel.parent_id,
                    target: $scope.firstlevel.id,
                });
                jsPlumb.repaintEverything();    
        })
        }
    }
});

Here is a diagram I did to help you visualize what I am trying to acomplish ( look at the text on the top right corner )

enter image description here

Georgi Angelov
  • 4,338
  • 12
  • 67
  • 96

2 Answers2

7

ngInclude provides an onload attribute which will evaluate an expression when it is loaded; does that give you what you need?

<div vector-draw-directive class="thirdlevel"
  ng-repeat="firstlevel in secondlevel.children"
  ng-include="'templateLevel2.html'" onload="loaded()">
</div>

Very basic example: http://jsfiddle.net/BinaryMuse/KRbdL/121/

Michelle Tilley
  • 157,729
  • 40
  • 374
  • 311
  • Yeah I tried using that but it still gives me the error : Cannot read property 'parentNode' of undefined: http://jsfiddle.net/GeorgiAngelov/KRbdL/125/ TypeError – Georgi Angelov Jul 12 '13 at 16:44
  • Even if you set a long `$timeout` inside `loaded`, it still does not work. I'm not familiar enough with the library you're using to really debug effectively. =\ – Michelle Tilley Jul 12 '13 at 16:50
  • I removed the library function to see if I can even get the elemeny with document.getElementById but neither of the elements seem to exist as it returns null.... here is the new fiddle http://jsfiddle.net/GeorgiAngelov/KRbdL/143/ – Georgi Angelov Jul 12 '13 at 18:10
  • But it works fine when using a `$timeout` of 0, which was my point in my last comment: http://jsfiddle.net/BinaryMuse/KRbdL/151/ A directive would usually handle any deferred DOM processing using `$timeout` like this (or just `setTimeout` if you don't need a digest cycle) – Michelle Tilley Jul 12 '13 at 20:01
  • I see. I was simply eerie of using $timeout. Where would I set the directive though to still have access to the firstlevel variable since I can't just inject it into the directive? – Georgi Angelov Jul 12 '13 at 20:11
  • Well, this example is a little different since the `ng-include`d templates only work inside existing scopes with the right variables set. I think I would probably turn each of them into a directive. In either case, you'd pass `firstlevel` into the directive via an attribute. – Michelle Tilley Jul 12 '13 at 20:50
1

You can kinda use the window.requestAnimationFrame callback to figure out when angular is done manipulating the DOM, like so:

var fn = function () {
    var elm = document.getElementById('elementID');

    if(elm == null) {
        window.requestAnimationFrame(fn);
    } else {
        doSomething();
    }
};
fn();

It's a hack though, so use at your own risk

Rasive
  • 1,143
  • 1
  • 8
  • 20