2

I have a simple app that uses Angular to run a HTTP GET request and then sets the returned data to an array that is bound to the DOM using ng-repeat and I want to run some code that manipulates this DOM after it is done being placed into the body. What is the best way to make this work?

            $http({
                method: 'GET',
                url: 'https://www.*******.com/WebApi/Alert/Items/all',
                cache: false
            })
            .success(function (data, status) {
                $scope.alerts = data.result.Alerts;
                jQuery('.aWidget').iconalt(); // THIS IS THE CODE I WANT TO RUN
            })
            .error(function (data, status) {
                console.log(data);
                alert("error");
            });

See, I want to run the line jQuery('.aWidget').iconalt() after all the DOM is placed into the document. Right now, this line is executing too fast and so it "thinks" that there are no .aWidget elements in the DOM

Is there some kind of callback that I can inject into AngularJS that gets called after the DOM is loaded?

Matt Hintzke
  • 7,744
  • 16
  • 55
  • 113
  • 1
    It is difficult to know when rendering in AngularJS is complete. The easiest and not so perfect way is to use $timeout with a decent lag. Or lopk at this SO post that tasks about how to know ng-repeat completed http://stackoverflow.com/questions/15207788/calling-a-function-when-ng-repeat-has-finished – Chandermani Jun 12 '14 at 02:06
  • I'd put the jQuery invocation into a simple directive and add it to your `ng-repeat` elements. It's a clean way forward without having to wrestle with Angular's digest and DOM-rendering pipeline by using constructs like `$timeout` or `$evalAsync`. – miqh Jun 12 '14 at 02:18

1 Answers1

1

You're running up against the digest cycle, which doesn't finish until your code returns. So what you REALLY need is to return but then run a piece of code AFTER that. There's a common JavaScript trick that does this:

// I used Angular's $timeout, but you can use setTimeout() just as easily...
$timeout(function() {
    jQuery('.aWidget').iconalt();
}, 50);

There is also a very cool module called setImmediate.js that polyfills the "setImmediate" function coming in modern browsers. This trick is used so often that browser makers realized it was something they should provide a fast, "correct" way to perform. Your code probably doesn't need to be run faster than 50ms later - the user will never notice... But if you were doing something that DID you could use this tool to run a task on the "next tick", so using the trick wouldn't be a performance hit.

Chad Robinson
  • 4,575
  • 22
  • 27