Image caching in angularjs - ngRepeat

I wanted to know how to implement image cache in AngularJS, or a way to load an image once and use it many times in one application

I need to show a list of directories in ui-select . The dropdown menu can contain folders or files. For folders I want to show the folder icon and for files I want to show the file icon. I am using ng-repeat to iterate over an array of files and folders

[ {name: "abc/", folder: true}, {name: "pqr.txt", folder: false}, ......]

      

Inside ng-repeat I have ng-if that shows the folder icon, if the folder-true attribute is else it shows the file icon. Right now I am using a tag to load an image. The image is in my local directory, will it slow down performance? Should I be using cache?

+3


source to share


3 answers


If you are not using a service $http

, you can use the $ cacheFactory service , which generates cache objects for all Angular Services. Internally, $ cacheFactory creates a default cache object even if we don't explicitly create it.

Then you can use a method put

that allows you to put the key (string) of any JavaScript object value into the cache.

cache.put(key, value);

      

You can access it



cache.get(key);

      

Or, if you are using $ http through the service, you can enable the cache by setting the parameter cache

to true:

$http({
   method: 'GET',
   url: '/api/users.json',
   cache: true
});

      

+3


source


As long as your image comes from the same url, your browser will automatically cache it.



+6


source


For anyone coming here from the Cordova / Phonegap + Angular mix; I ran into an issue where I didn't like any of the solutions available and the seemingly popular christen / imgcache plugin solution was not worth it after due to lack of OS support (it looks like chrome is the only OS supported) a href = " https://github.com/chrisben/imgcache.js/ "rel =" nofollow "> https://github.com/chrisben/imgcache.js/

So, I decided to write an AngularJS directory that handles the whole process by simply adding a "cacheimg" attribute to any img / element with a background image.

The basis of the following is that it downloads and writes image files to temporary storage on the device using the cordova file + filetransfer plugins (both are required for this plugin to work!)

var LOG_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 modified
                findImageURLs(elem, attrs);

            }, true);

            scope.$watch(function () {
                return attrs.src;
            },  function(){

                // Image source has been changed so check image hasn't been modified
                findImageURLs(elem, attrs);

            }, true);


            // Do an initial search for anything pre-set
            findImageURLs(elem, attrs);

        }
    };
});

function findImageURLs(elem, attrs){
    // Check for  background image
    if (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 tag
    if (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 cache
function buildFileKey(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 time
function GetFromCache(sourceUrl, success, fail) {
    console.log(LOG_TAG + 'Getting image from the cache');
    var FOLDER_IMAGE_CACHE = 'IMAGE_CACHE';
    var fileKey = buildFileKey(sourceUrl);
    var cacheExpiry = new Date().getTime() - (86400000 * 3); // 3 days

    // Get the file system for temporary storage
    window.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 file
            doesFileExist(dirEntry, fileKey, function(fileEntry){

                // File exists - check if it needs to be renewed
                if (new Date(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 path
                console.log(LOG_TAG + 'Passing back the image path ' + fileEntry.toURL());
                return (success(fileEntry.toURL()));

            }, function(){

                // File does not exist so download
                console.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 cache
function doesFileExist(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 cache
function downloadFile(url, downloadToPath, success, fail){
    console.log(LOG_TAG + 'Downloading file ' + url);
    var fileTransfer = new FileTransfer();

    // 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 errors
            console.log(LOG_TAG + 'Download Failed: ' + error.source);
            //alert("download error target " + error.target);
            //alert("upload error code" + error.code);
        }
    );

}

      

So, for everyone who doesn't know how to deal with the above (and I apologize if this method isn't very "w501>" - I'm still pretty new to Angular)! just copy the code, paste it into a new file in your projects js folder, make sure you include this file in your project:

<script type="text/javascript" src="js/directives/dir_imgcache.js"></script>

      

Change "app.directive" to be [yourappname] .directive, you can just add "cacheimg" attribute to your element ...

// Handling a background-image source
<div cacheimg style="background-image:url(img/myimage.png);"></div>

// Handling an image element source
<img cacheimg src="img/myimage.png" />

// Handling a AngularJS scoped image background source
<div cacheimg style="background-image:url({{ item.myimagesource }});"></div>

      

For the purpose of the last example, I had to stand in $ watch because the directive is called before the background image is set! Unless you plan on setting an image from a variable scope, I highly recommend removing $ watch!

It's also worth mentioning that I haven't added delete at this time - it's good practice not to rely on the OS to delete files, so I plan to adapt this directory further to delete any image that hasn't been requested for a while.

Anyway, hope someone helps! :)

+1


source







All Articles