Search code examples
angularjsng-animate

Dynamically Generated ID's--null targets


Kudos to EricWVGG for his animation directives.

I am using the following html and angularJS directives to perform slide animations. I am having trouble getting individual elements in the ngRepeat to be targeted. When I leave the div ID as a constant throughout all indices, the animation works. When I attach the $index to the div ID, a 'target is null' error is displayed in Firebug.

<div>
    <div class="title" slide-toggle="#row_{{$index}}">
        <div style="float: left; width: 100%;">
         </div>
    </div>
    <div id="row_{{$index}}" class="slideable" duration=".5s">
    </div>
</div>


.directive('slideable', function () {
return {
    restrict:'C',
    compile: function (element, attr) {
        // wrap tag
        var contents = element.html();
        element.html('<div class="slideable_content" style="margin:0 !important; padding:0 !important" >' + contents + '</div>');

        return function postLink(scope, element, attrs) {
            // default properties
            attrs.duration = (!attrs.duration) ? '1s' : attrs.duration;
            attrs.easing = (!attrs.easing) ? 'ease-in-out' : attrs.easing;
            element.css({
                'overflow': 'hidden',
                'height': '0px',
                'transitionProperty': 'height',
                'transitionDuration': attrs.duration,
                'transitionTimingFunction': attrs.easing
            });
        };
    }
};
})

.directive('slideToggle', function() {
return {
    restrict: 'A',
    link: function(scope, element, attrs) {
        var target = document.querySelector(attrs.slideToggle);
        attrs.expanded = false;
        element.bind('click', function() {
            var content = target.querySelector('.slideable_content');
            if(!attrs.expanded) {
                content.style.border = '1px solid rgba(0,0,0,0)';
                var y = content.clientHeight;
                target.style.height = y + 'px';
            } else {
                target.style.height = '0px';
            }
            attrs.expanded = !attrs.expanded;
            }


        });
    }
};
})

Solution

  • The $index is only reachable inside a ng-repeat directive which is actually missing in your code.

    You also need the $timeout function with a 0 value to wait Angular finish update the DOM before execute your code, otherwise all the divs with ids row_X where X is the computed value of $index will stay as row_{{$index}} and you will not be able to target them. (here and here for more infos about it)

    Here is a JSFiddle for your example code.