1

I've an example to get json from server and append it to a list.

Script:

$http.get('/data/json/cities.json').then(function (res) {
    if (res.status === 200) {
        $scope.cities = res.data;
    }
});

Html:

<li ng-repeat="(id, name) in cities" id="{{id}}">
    <a href="#" ng-bind="name"></a>
</li>

The code where I'm stuck:

if (res.status === 200) {
    $scope.cities = res.data;

    // from here
    console.log($('li#NY').length); // 0

    // waiting 1 second and try again
    setTimeout(function () {
        console.log($('li#NY').length); // 1
    }, 1000);
}

The json object contains the key NY but I can only assign to the object (li tag with id NY) after 1 second (or longer).

Is there another way to know when an object ($('li#NY') in this case) has been created successful without using setTimeout?

  • what are you trying to do exactly? it's not clear from the code why you need this information. – Karim May 26 '17 at 16:30
  • Try use `ng-repeat-end` directive – Hadi J May 26 '17 at 16:30
  • @Karim What's unclear? The list contains `$('li#NY')` object, and the object will be created after I get the json. But when I get the json, I can only assign to the object after 1 second. –  May 26 '17 at 16:33
  • 1
    @Hadi `ng-repeat-start` & `ng-repeat-end` will help to place start and end point of directive template(multi template repeat).. I guess OP needs [ng-repeat finish event](https://stackoverflow.com/a/13472605/2435473) answer.. – Pankaj Parkar May 26 '17 at 16:34
  • @PankajParkar Thanks for the link. I've just checked again. Inside the directive, I have to wait 1 second at least to check length. –  May 26 '17 at 16:50

1 Answers1

1

You have to create a directive, follow code below.

var module = angular.module('app', [])
        .directive('onFinishRender', function ($timeout) {
        return {
            restrict: 'A',
            link: function (scope, element, attr) {
                if (scope.$last === true) {
                    $timeout(function () {
                        scope.$emit(attr.onFinishRender);
                    });
                }
            }
        }
    });

And then in your controller, you can catch it with $on:

$scope.$on('ngRepeatFinished', function(ngRepeatFinishedEvent) {
    //you also get the actual event object
    //do stuff, execute functions -- whatever...
    console.log($('li#NY').length); // 1
});

With html that looks something like this:

<li ng-repeat="(id, name) in cities" id="{{id}}" on-finish-render="ngRepeatFinished">
    <a href="#" ng-bind="name"></a>
</li>
LXhelili
  • 980
  • 5
  • 14
  • 1
    It works. Thank you! Can you explain me why do I need `$timeout` there? –  May 26 '17 at 17:00
  • 1
    $timeout makes sure it's executed when the ng-repeated elements have REALLY finished rendering (because the $timeout will execute at the end of the current digest cycle -- and it will also call $apply internally, unlike setTimeout). So after the ng-repeat has finished, we use $emit to emit an event to outer scopes (sibling and parent scopes). – LXhelili May 26 '17 at 17:05