2

I'm trying to create my own image carousel as an angularjs directive; I want to keep it as lightweight and unopinionated as possibile, so I thought I'd just create a <carousel></carousel> wrapper for a set of <img> elements, like so:

<carousel>
   <img ng-repeat="image in images" ng-src="{{image.src}}" alt=""/>
</carousel>

What the directive does is to simply create a <div class="carousel"> element into which the images are transcluded. Now, I still haven't coded the part where images slide or fade in/out cause there's one issues I'd like to get out of the way first: I want to assign the carousel and all the images therein the same height (computed as the height of the shortest image) so as to avoid the carousel from changing height when a taller image gets displayed, or avoid cropping the image in case the carousel had a fixed height.

So I jotted down this JSFiddle to demonstrate, but so far the best solution I found to compute the heights of the transcluded images relies on two nested $timeouts with a 100-ms delay. It looks to me more like a hack than anything.
So I was wondering if there's a "proper" way to accomplish it in angularjs. Cheers.

P.S. On a side note, I also dislike fetching the root element of the directive's template, the <div class="carousel"> in my case, using element.children()... is there no easy way to reference it in angularjs? Looked around but no dice.

3
  • because without $timeout your directive will run before ng-repeat finishes rendering of img tags Commented May 29, 2015 at 11:35
  • 1
    Excellent approach, kudos. :) Commented May 30, 2015 at 10:35
  • Yes..I thought that I implemented that..& it works..Glad to help you..:) Commented May 30, 2015 at 10:40

1 Answer 1

3

You need to write one more directive that will be intimate angular code that ng-repeat rendered all the img tags then on that we will add listener event which will set the height and width of that element on load of that image.

Directive

.directive("carousel", ["$timeout", function ($timeout) {
    return {
        restrict: "E",
        transclude: true,
        template: "<div class=\"carousel\" ng-transclude></div>",
        link: function (scope, element, attrs) {
            var div = element.children();
            scope.$on('ngRepeatDone', function () {
                element.find('img').on('load', function () {
                    var images = div.children();
                    var minHeight = Math.min.apply(null, _.pluck(images, "height"));
                    angular.forEach([div, images], function (e) {
                        e.css({
                            height: minHeight + "px"
                        });
                    });
                    scope.$apply();
                });
            });
        }
    }
}])

NgRepeateDone

.directive('myPostRepeatDirective', function () {
    return function (scope, element, attrs) {
        if (scope.$last) {
            scope.$emit('ngRepeatDone')
        }
    };
});

Demo JSFiddle

Sign up to request clarification or add additional context in comments.

1 Comment

@Jai yes..here we need it because we are doing scope manipulation on DOM event like here its .on('load')

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.