Reputation: 16261
I would like to lazy load images and iframes (i.e. set the src once the element is in the viewport). I have an existing angular directive is-visible
that sets the is-visible
attribute when an element scrolls into view. How do I reuse this directive from within my set-src-when-visible
directive?
i.e., I want this code to reuse the is-visible
directive:
<img set-src-when-visible="http://example.com/img.png" />`
<iframe set-src-when-visible="http://example.com/" />
is-visible
directiveI can require the is-visible
directive to be on the same element I am declaring the set-src-when-visible
directive on:
<img set-src-when-visible="url" is-visible />
myApp.directive('setSrcWhenVisible', function () {
return {
restrict: 'A',
require: 'isVisible',
link: function ($scope, element, attrs) {
var set = false;
attrs.$observe('isVisible', function(isVisible) {
if(isVisible && !set) {
attrs.$set('src', $scope.$eval(attrs.setSrcWhenVisible));
set = true;
}
});
}
}
});
Here is a working example: http://jsfiddle.net/pvtpenguin/6tCk6/
Downside: I'd like to be able to specify only the set-src-when-visible
directive while still reusing is-visible
.
Create two directives, one for iframe and one for img tag:
<iframe set-iframe-src-when-visible="url"></iframe>
<img set-img-src-when-visible="url" />
angular.forEach(['Iframe', 'Img'], function(tagName) {
var directiveName = 'set' + tagName + 'SrcWhenVisible';
myApp.directive(directiveName, function ($window) {
return {
restrict: 'A',
template: '<' + tagName + ' is-visible></' + tagName + '>',
replace: true,
link: function ($scope, element, attrs) {
var set = false;
attrs.$observe('isVisible', function(value) {
if(value && !set) {
attrs.$set('src', $scope.$eval(attrs[directiveName]));
set = true;
}
});
}
}
});
});
Working example: http://jsfiddle.net/pvtpenguin/K4JuC/2/
Downside: different names for each directive, plus this doesn't fit well with the method I am using to declare and configure my app.
Upvotes: 1
Views: 571
Reputation: 364677
Based on our comment discussion, here is a link function that hopefully will do what you want:
link: function ($scope, element, attrs) {
$scope.src = attrs.setSrcWhenVisible; // save attribute -- is $eval needed?
var tagName = element[0].tagName;
if(tagName == 'IMG') {
var jqLiteWrappedElement = angular.element('<img is-visible></img>');
} else {
var jqLiteWrappedElement = angular.element('<iframe is-visible></iframe>');
}
element.replaceWith(jqLiteWrappedElement);
$compile(jqLiteWrappedElement)($scope);
var set = false;
attrs.$observe('isVisible', function(value) {
if(value && !set) {
attrs.$set('src', $scope.src);
set = true;
}
});
}
Upvotes: 1