Caching Images In Angularjs - Ngrepeat
Solution 1:
As long as your image is coming from the same URL, your browser will do the caching automatically.
Solution 2:
If you are not using through an $http
service you might use the $cacheFactory service that generates cache objects for all Angular services. Internally,
the $cacheFactory creates a default cache object, even if we don’t create one explicitly.
Then you can use the the put
method which allows to to put a key (string) of any JavaScript object value into the
cache.
cache.put(key, value);
You can access it by
cache.get(key);
Or if you are using through $http service you can enable the cache by setting the cache
parameter as true:
$http({
method: 'GET',
url: '/api/users.json',
cache: true
});
Solution 3:
For anyone coming here from a Cordova/Phonegap + Angular mix; I was running into the issue where I didn't like any of the solutions available and the seemingly popular solution of the christen/imgcache plugin wasn't worth following due to lack of OS support (Looks like chrome is the only OS supported) https://github.com/chrisben/imgcache.js/
So I decided to write an AngularJS directory that handles the entire process simply by adding a "cacheimg" attribute on any img/element with background image.
The basics of the following are that it downloads and writes the image files into temporary storage on the device using the cordova file + filetransfer plugins (Both are required for this plugin to work!)
varLOG_TAG = 'DIR_IMGCACHE: ';
app.directive('cacheimg', function() {
return {
restrict: 'A',
link: function(scope, elem, attrs) {
console.log(LOG_TAG + 'Starting Directive.');
// Watch any value changes
scope.$watch(function () {
return elem.css(attrs.style);
}, function(){
// Style has been changed so check image hasn't been modifiedfindImageURLs(elem, attrs);
}, true);
scope.$watch(function () {
return attrs.src;
}, function(){
// Image source has been changed so check image hasn't been modifiedfindImageURLs(elem, attrs);
}, true);
// Do an initial search for anything pre-setfindImageURLs(elem, attrs);
}
};
});
functionfindImageURLs(elem, attrs){
// Check for background imageif (elem.css('background-image') !== 'none'){
console.log(LOG_TAG + 'Background Image');
var backimgsrc = elem.css('background-image');
if (backimgsrc.startsWith('url(')){
backimgsrc = backimgsrc.substring(4, backimgsrc.length -1);
}
// Retrieve from the cache (or download if we havent already)GetFromCache(backimgsrc, function(imgPath){
console.log(LOG_TAG + 'Got image - setting now');
// Got the image, set it now
elem.css('background-image', 'url(' + imgPath + ')');
}, function(err){
console.log(LOG_TAG + 'Failed to get image from cache');
// SET BROKEN LINK IMAGE HERE
elem.css('background-image', 'url(../../img/brokenlink.png)');
});
}
// Check for a src tagif (attrs.src !== undefined){
console.log(LOG_TAG + 'Found Src Tag');
// Retrieve from the cache (or download if we havent already)GetFromCache(attrs.src, function(imgPath){
console.log(LOG_TAG + 'Got image - setting now');
// Got the image, set it now
attrs.$set('src', imgPath);
}, function(err){
console.log(LOG_TAG + 'Failed to get image from cache');
// SET BROKEN LINK IMAGE HERE
attrs.$set('src', '../../img/brokenlink.png');
});
}
}
// Build a file key - this will be what the filename is within the cachefunctionbuildFileKey(url){
console.log(LOG_TAG + 'Building file key for url: ' + url);
var parts = url.split('.');
var result = (parts.slice(0,-1).join('') + '.' + parts.slice(-1)).toString().replace(/[\/,:]/g,'_').toLowerCase();
console.log(LOG_TAG + 'Built file key: ' + result);
return result;
}
// Either get hold of the file from the cache or if we don't currently have it// then attempt to download and store in the cache ready for next timefunctionGetFromCache(sourceUrl, success, fail) {
console.log(LOG_TAG + 'Getting image from the cache');
varFOLDER_IMAGE_CACHE = 'IMAGE_CACHE';
var fileKey = buildFileKey(sourceUrl);
var cacheExpiry = newDate().getTime() - (86400000 * 3); // 3 days// Get the file system for temporary storagewindow.requestFileSystem(window.TEMPORARY, 5 * 1024 * 1024, function(fs){
console.log(LOG_TAG + 'Opened File System: ' + fs.name);
// Get hold of the directory (Or create if we haven't already)
fs.root.getDirectory(FOLDER_IMAGE_CACHE, { create:true }, function(dirEntry){
var downloadToPath = dirEntry.toURL() + fileKey;
// Check to see if we have the filedoesFileExist(dirEntry, fileKey, function(fileEntry){
// File exists - check if it needs to be renewedif (newDate(fileEntry.lastModifiedDate).getTime() < cacheExpiry){
console.log(LOG_TAG + 'Image has passed the expiry threshold - re-getting the file');
downloadFile(sourceUrl, downloadToPath, success, fail);
}
// Return the file pathconsole.log(LOG_TAG + 'Passing back the image path ' + fileEntry.toURL());
return (success(fileEntry.toURL()));
}, function(){
// File does not exist so downloadconsole.log(LOG_TAG + 'Image doesnt exist - getting file');
downloadFile(sourceUrl, downloadToPath, success, fail);
});
}, fail);
}, fail);
}
// Check to see if the given image already exists in our cachefunctiondoesFileExist(dir, fileKey, existsCallback, notExistsCallback){
console.log(LOG_TAG + 'Checking if file exists');
// Check the directory for this file
dir.getFile(fileKey, { create:false }, function(fileEntry){
existsCallback(fileEntry);
}, notExistsCallback);
}
// Download a file into the cachefunctiondownloadFile(url, downloadToPath, success, fail){
console.log(LOG_TAG + 'Downloading file ' + url);
var fileTransfer = newFileTransfer();
// File download function with URL and local path
fileTransfer.download(encodeURI(url), downloadToPath,
function (fileEntry) {
console.log(LOG_TAG + 'Download Complete to path: ' + fileEntry.toURL());
success(fileEntry.toURL());
},
function (error) {
//Download abort errors or download failed errorsconsole.log(LOG_TAG + 'Download Failed: ' + error.source);
//alert("download error target " + error.target);//alert("upload error code" + error.code);
}
);
}
So for anyone unsure how to handle the above (and I apologise if this method is not 'very angular' - I'm still fairly new to Angular myself!) simply copy the code, stick it into a new file in your projects js folder, make sure you include this file in the project:
<scripttype="text/javascript"src="js/directives/dir_imgcache.js"></script>
Change the "app.directive" to be [yourappname].directive, you can then just add the attribute "cacheimg" to your element...
// Handling a background-image source
<div cacheimg style="background-image:url(img/myimage.png);"></div>
// Handling an image element source<imgcacheimgsrc="img/myimage.png" />// Handling a AngularJS scoped image background source<divcacheimgstyle="background-image:url({{ item.myimagesource }});"></div>
For the purpose of the last example I had to stick in a $watch because the directive gets called prior to the background image being set! If you don't plan on setting an image from a scope variable I strongly recommend removing the $watch!
It is also worth mentioning that currently I haven't put in a delete - it is good practise to not rely on the OS to delete files so I plan on adapting this directory further to remove any image not requested for a while.
Anyway, hope that helps someone! :)
Post a Comment for "Caching Images In Angularjs - Ngrepeat"