diff --git a/README.md b/README.md index c9920cf..d6392ef 100644 --- a/README.md +++ b/README.md @@ -102,7 +102,8 @@ You can put more than one template script in your template file, just make sure ``` -The load service comes with a second optional parameter that you can use if you need to define some configuration for the requests (check: https://docs.angularjs.org/api/ng/service/$http#usage) but it only works with the templates (js and css default loaders don't use `$http`). +The load service comes with a second optional parameter that you can use if you need to define some configuration for the requests (check: https://docs.angularjs.org/api/ng/service/$http#usage). +The parameter `cache: false` works for all native loaders (**all requests are cached by default**), other parameters only works with the templates for now (js and css default loaders don't use `$http`). ```js $ocLazyLoad.load( ['partials/template1.html', 'partials/template2.html'], diff --git a/src/ocLazyLoad.js b/src/ocLazyLoad.js index 213986d..1eaa2f0 100644 --- a/src/ocLazyLoad.js +++ b/src/ocLazyLoad.js @@ -2,14 +2,12 @@ 'use strict'; var regModules = ['ng'], regInvokes = [], - filesLoaded = [], ocLazyLoad = angular.module('oc.lazyLoad', ['ng']), broadcast = angular.noop; ocLazyLoad.provider('$ocLazyLoad', ['$controllerProvider', '$provide', '$compileProvider', '$filterProvider', '$injector', '$animateProvider', function($controllerProvider, $provide, $compileProvider, $filterProvider, $injector, $animateProvider) { var modules = {}, - templates = [], providers = { $controllerProvider: $controllerProvider, $compileProvider: $compileProvider, @@ -26,8 +24,9 @@ // Let's get the list of loaded modules & components init(angular.element(window.document)); - this.$get = ['$timeout', '$log', '$q', '$templateCache', '$http', '$rootElement', '$rootScope', function($timeout, $log, $q, $templateCache, $http, $rootElement, $rootScope) { - var instanceInjector; + this.$get = ['$timeout', '$log', '$q', '$templateCache', '$http', '$rootElement', '$rootScope', '$cacheFactory', function($timeout, $log, $q, $templateCache, $http, $rootElement, $rootScope, $cacheFactory) { + var instanceInjector, + filesCache = $cacheFactory('ocLazyLoad'); if(!debug) { $log = {}; @@ -41,9 +40,7 @@ }; broadcast = function broadcast(eventName, params) { - // console.log('broadcast'); if(events) { - // console.log(arguments); $rootScope.$broadcast(eventName, params); } } @@ -54,21 +51,32 @@ * @param path * @returns promise */ - var buildElement = function buildElement(type, path) { + var buildElement = function buildElement(type, path, params) { var deferred = $q.defer(), - el, loaded; + el, loaded, + cacheBuster = function cacheBuster(url) { + var dc = new Date().getTime(); + if(url.indexOf('?') != -1) { + if(url.substring(0, url.length - 1) === '&') { + return url + '_dc=' + dc; + } + return url + '&_dc=' + dc; + } else { + return url + '?_dc=' + dc; + } + }; - // Switch in case more content types are added later (for example a native JS loader!) + // Switch in case more content types are added later switch(type) { case 'css': el = document.createElement('link'); el.type = 'text/css'; el.rel = 'stylesheet'; - el.href = path; + el.href = params.cache === false ? cacheBuster(path) : path; break; case 'js': el = document.createElement('script'); - el.src = path; + el.src = params.cache === false ? cacheBuster(path) : path; break; default: deferred.reject(new Error('Requested type "' + type + '" is not known. Could not inject "' + path + '"')); @@ -78,14 +86,13 @@ if((el['readyState'] && !(/^c|loade/.test(el['readyState']))) || loaded) return; el.onload = el['onreadystatechange'] = null loaded = 1; - if(filesLoaded.indexOf(path) === -1) { - filesLoaded.push(path); - broadcast('ocLazyLoad.fileLoaded', path); + if(angular.isUndefined(filesCache.get(path))) { + filesCache.put(path, true); } + broadcast('ocLazyLoad.fileLoaded', path); deferred.resolve(); } el.onerror = function(e) { - console.log('error'); deferred.reject(new Error('Unable to load '+path)); } el.async = 1; @@ -100,12 +107,13 @@ * @type Function * @param paths array list of js files to load * @param callback to call when everything is loaded. We use a callback and not a promise + * @param params object config parameters * because the user can overwrite jsLoader and it will probably not use promises :( */ - jsLoader = function(paths, callback) { + jsLoader = function(paths, callback, params) { var promises = []; angular.forEach(paths, function loading(path) { - promises.push(buildElement('js', path)); + promises.push(buildElement('js', path, params)); }); $q.all(promises).then(function success() { callback(); @@ -122,12 +130,13 @@ * @type Function * @param paths array list of css files to load * @param callback to call when everything is loaded. We use a callback and not a promise + * @param params object config parameters * because the user can overwrite cssLoader and it will probably not use promises :( */ - cssLoader = function(paths, callback) { + cssLoader = function(paths, callback, params) { var promises = []; angular.forEach(paths, function loading(path) { - promises.push(buildElement('css', path)); + promises.push(buildElement('css', path, params)); }); $q.all(promises).then(function success() { callback(); @@ -143,42 +152,33 @@ * templatesLoader function * @type Function * @param paths array list of css files to load - * @param params object config parameters for $http * @param callback to call when everything is loaded. We use a callback and not a promise + * @param params object config parameters for $http * because the user can overwrite templatesLoader and it will probably not use promises :( */ - templatesLoader = function(paths, params, callback) { + templatesLoader = function(paths, callback, params) { if(angular.isString(paths)) { paths = [paths]; } - if(angular.isFunction(params)) { - callback = params; - params = {}; - } - if(angular.isUndefined(params)) { - params = {}; - } var promises = []; angular.forEach(paths, function(url) { var deferred = $q.defer(); promises.push(deferred.promise); - if(templates.indexOf(url) === -1 || (angular.isDefined(params) && params.cache === false)) { - $http.get(url, params).success(function(data) { - angular.forEach(angular.element(data), function(node) { - if(node.nodeName === 'SCRIPT' && node.type === 'text/ng-template') { - $templateCache.put(node.id, node.innerHTML); - } - }); - templates.push(url); - deferred.resolve(); - }).error(function(data) { - var err = 'Error load template "' + url + '": ' + data; - $log.error(err); - deferred.reject(new Error(err)); + $http.get(url, params).success(function(data) { + angular.forEach(angular.element(data), function(node) { + if(node.nodeName === 'SCRIPT' && node.type === 'text/ng-template') { + $templateCache.put(node.id, node.innerHTML); + } }); - } else { + if(angular.isUndefined(filesCache.get(url))) { + filesCache.put(url, true); + } deferred.resolve(); - } + }).error(function(data) { + var err = 'Error load template "' + url + '": ' + data; + $log.error(err); + deferred.reject(new Error(err)); + }); }); return $q.all(promises).then(function success() { callback(); @@ -196,12 +196,14 @@ promises = []; angular.forEach(paths, function(path) { - if(/\.css[^\.]*$/.test(path)) { - cssFiles.push(path); - } else if(/\.(htm|html)[^\.]*$/.test(path)) { - templatesFiles.push(path); - } else { - jsFiles.push(path); + if(angular.isUndefined(filesCache.get(path)) || params.cache === false) { + if(/\.css[^\.]*$/.test(path)) { + cssFiles.push(path); + } else if(/\.(htm|html)[^\.]*$/.test(path)) { + templatesFiles.push(path); + } else { + jsFiles.push(path); + } } }); @@ -214,20 +216,20 @@ } else { cssDeferred.resolve(); } - }); + }, params); promises.push(cssDeferred.promise); } if(templatesFiles.length > 0) { var templatesDeferred = $q.defer(); - templatesLoader(templatesFiles, params, function(err) { + templatesLoader(templatesFiles, function(err) { if(angular.isDefined(err) && templatesLoader.hasOwnProperty('ocLazyLoadLoader')) { $log.error(err); templatesDeferred.reject(err); } else { templatesDeferred.resolve(); } - }); + }, params); promises.push(templatesDeferred.promise); } @@ -240,7 +242,7 @@ } else { jsDeferred.resolve(); } - }); + }, params); promises.push(jsDeferred.promise); } @@ -278,11 +280,15 @@ moduleName, errText; + if(angular.isUndefined(params)) { + params = {}; + } + // If module is an array, break it down if(angular.isArray(module)) { // Resubmit each entry as a single module angular.forEach(module, function(m) { - deferredList.push(self.load(m)); + deferredList.push(self.load(m, params)); }); // Resolve the promise once everything has loaded @@ -404,7 +410,7 @@ // Check if the dependency has any files that need to be loaded. If there are, push a new promise to the promise list. if(requireEntry.hasOwnProperty('files') && requireEntry.files.length !== 0) { if(requireEntry.files) { - promisesList.push(filesLoader(requireEntry.files).then(function() { + promisesList.push(filesLoader(requireEntry.files, params).then(function() { return loadDependencies(requireEntry) })); } @@ -415,7 +421,7 @@ return $q.all(promisesList); } - filesLoader(config.files).then(function success() { + filesLoader(config.files, params).then(function success() { if(moduleName === null) { deferred.resolve(module); } else {