Clear Angular JS templateCache once (for each deployment) - javascript

This issue AngularJS disable partial caching on dev machine suggests using $templateCache.removeAll() to clear the cache templates. However what if you just want to fire this once upon each deployment cycle in order to get visitor browsers to refresh/update the template? Our problem was some browsers were not updating the template html files, we'd end up with new CSS mixed with old HTML. I do not want this function to fire all the time, that would defeat the point of cache templates to begin with (right?).
Per the title question, what's a recommended way to clear $templateCache "once", for example some ideas I've crunched:
Does Angular have an internal method of detecting if the template file has changed? And then if so "update" it.
Does Angular have an internal "version" or "date" we could compare and add a conditional to fire function removeAll()?
Does $templateCache ever itself know to refresh? What were the Angular creator's intentions in forcing templateCache on us if HTML files are bound to change overtime and served to multiple browsers.
I do not want to use grunt to add workflow overhead for something that happens periodically, nor to chop up the html file templates into variables. (Is this a good method for template cache busting in angular?)
The alternative I can see is simply adding and removing removeAll() code manually, that would be silly.

We decided to go with simply tacking on UNIX timestamp version to files which were changed like file.php?v=154325232. The reason being we weren't actually using Angular templateCache, in that we weren't storing the template data itself inside templateCache. I thought Angular automatically stores any async loaded directive template files into templateCache, thats not true, you have to explicitly use templateCache to get a file (Good tutorial on that https://thinkster.io/templatecache-tutorial).
So our solution is just boring old versioning, which is most understandable by browser headers and for non-mega-scaling websites, just fine.
$modifiedTs = filemtime($filename);
if ($modifiedTs != $lastModificationTs){
echo "$filename?v=" . time();
}
How to check if a file has changed?
Lastly the way I read templateCache, its not intended to save data between browser sessions rather its a cache service during the session. It has nothing to do with the browser cache, rather Angular stores it internally. So its meant for websites that dynamically navigate and load URLs (ie: not a true page refresh but an AJAX trick) which is how most of Google websites are today.
Prevent browser cache of angular templates
Best way to manually clear out $templateCache in AngularJS

The current popular method is to create a task using a node module that preprocesses Angular templates into a file in which you add into the js stack.
You could install gulp-ng-html2js and make it a gulp task. This would output a file say templates.js, which you then add to the head.
https://www.npmjs.com/package/gulp-ng-html2js
Then call it out in your app as a module dependency. app.module('myApp',['templates']);
So before each deployment, run this gulp task.
And if needed add a cache breaker query string templates.js?v=123

Related

How to read javascript file in frontend javascript/browser

Please read carefully before marking as dupe.
I want to read a javascript file on frontend. The javascript file is obviously being used as a script on the webpage. I want to read that javascript file as text, and verify if correct version of it is being loaded in the browser. From different chunks of text in the js file, I can identify what version is actually being used in the end user's browser. The js file is main.js which is generated by angular build.
I know we can do something like creating a global variable for version or some mature version management. But currently, on production site, that will mean a new release, which is couple of months from now. Only option I have right now is html/js page, which can be directly served from production site, without waiting for new release.
So my question is, is it possible we can read a javascript file as text in hmtl/js code in the browser.
an idea can be :
use fetch api to get a container that can be use to async load the script
https://developer.mozilla.org/en-US/docs/Web/API/Fetch_API
use text() method which return a promise to get text content
fetch('http://localhost:8100/scripts.js').then((res) => res.text()).then(scriptContent => {
// scriptContent contain the content of your script
// if (scriptContent.includes('version : 1.1.1')
console.log(scriptContent);
});
this is absolutely not an efficient way, but since you want to work without any new version release or working with a version management system
here is the thing
assume file's checksum (md5 sha125 or anything) of V1.0 equals X and you will calculate before the coding part.
if checksum(X) != X{
location.reload()
}
would help for a security features too since it's an important project.
another way of controlling this situation is changing the main.js file's name if it is possible.

Is it possible to influence a single Angular app from multiple JS scripts?

Quick Summary:
I need to allow two script files to handle different operations for the same angular app. One needs to initialize the app, the other needs to assign a templateCache object to a piece of JSON in localStorage.
Context:
I have several python files which compile/generate html and I have constructed an angular app with this emitted html for my site (which uses CGIs).
The basic construct of the site comes pieces of HTML, which fit together like so:
|------------Header---------------|
|-Navigation-|------Content-------|
|-Navigation-|------Content-------|
|-Navigation-|------Content-------|
|------------Footer---------------|
My Header creates the <head> tag, instantiates my ng-app and uses $templateCache to set up a template that I call from my Navigation code. I had to go with templateCache instead of ngView and ngRoute due to some limitations with how the CGIs emit the html, and the order in which this happens.
My "Navigation" python/html sets up my app with JS like so:
<script>
var responsiveCatalog = angular.module('responsiveCatalog', ['ngStorage']);
....controllers...
....config, etc....
</script>
This Navigation also includes my default templateCache object:
<div ng-include=" 'responsiveItems.html' "></div>
This is all working to show my first templateCache object in the Content section. However, I need to grab many pieces of information from the python generator for the "Content" section (a totally separate file from the "Navigation"), store this data as JSON in localstorage (hence the inclusion of the ngStorage module), and call that as my second templateCache option.
I am not actually sure that I can use two separate instances of Javascript to reference and influence the same Angular app. I know this seems like bad practice, but I am trying to prevent the need to tear down a huge piece of legacy architecture to influence the angular app from two Javascript files in harmony.
Thanks in advance.
You can do
angular.module('myAppName').controllers.... in different files, just make sure the myAppName the same. Bug I don't feel like it work with config, no time to test. If you need any communication between them, check $emit and $broadcast.

Accessing Angular app's props and controller functions from external non-Angular plugins

I have an Angular SPA but in it I'm using some non-angular library (Medium Editor [ME from now on] to be exact). I created a directive for ME so if I add a contenteditable element on my views, ME get's instantiated and works properly. So that's not a problem.
The problem is that I also created a special ME extension that requires to make web requests to my server in order to insert correct markup into ME's editable element. But to make these requests it requires some view-model's data and also communicate it back:
it needs to read and set (when undefined) my view model ID
it needs to constantly manipulate some other view model value in order for my SPA to know that it's still processing so other processes get postponed
I thought I'd simply include input type="hidden" ng-model="..." on my page and change its value and trigger input event so Angular would update its model. Hidden input of course doesn't work. So I changed it to input type="text" class="hidden" and keep the functionality.
This does work, but it doesn't seem to be the proper way of doing things as it's hackish. And this mainly works for model value exchange (get/set). How about if I would have to call some controller function? Is that even remotely possible?
I don't want to make ME's extension to rely in any way on Angular library as it has to be purely ME extension and should be reused in non-Angular SPAs (maybe some other lib SPA or just pure simple DHTML web app). But I would like to make it usable in SPAs as well as ME can easily be used to manipulate some element's markup that can be set to view model through a directive.
What it the proper way of communicating with Angular app from external libs that aren't native to Angular?
Additional info
Basically I want to have 4 functions in my custom extension that should somehow access (and manipulate) my Angular view model:
getReferenceId() and setReferenceId(id)
incrementPending() and decrementPending()
Pending counter could be exposed publicly and accessed by my Angular SPA, so it wouldn't process data while extension is still doing its own stuff. But SPA doesn't have any authority over when to set reference ID so it would correctly be read by the extension...
This is usually solved by wrapping external plugins (or their parts) in ng services and directives. You don't need the input tag, just put the data on scope and after changing from non-ng code call $scope.$digest. If you need to watch for data change to trigger something in external library, you can use either ng-change or $scope.$watch.

Prevent require.js from caching text files?

I'm loading a rather large text file using the require.js text plugin. It is required by a module that parses it as JSON and uses the data to hydrate some models. After that, the original text is no longer needed.
As far as I know require.js keeps everything it has loaded in memory. Is there a way to prevent that?
Another option would be to load the text file manually via AJAX but doing it via require.js would be much more convenient.
I do NOT want cache busting solutions. The file is only loaded one time and I just don't want to keep it in memory when I no longer need it.
According to the requirejs doocumentation you can "undef" a module:
http://requirejs.org/docs/api.html#undef
This won't free memory for pieces of your code that have already required the module, but for those you could unset the local version via my_module = undefined.

Forcing the browser to reload css/js only if they have changed

There are a lot of questions and answers on SO related to my problem [I want the browser to cache js/css forever. During a new release if some of the js/css files have been updated, the browser should reload and cache them.]
This solution seemed most appropriate to me :
What is an elegant way to force browsers to reload cached CSS/JS files?
However, there is just one thing that I am unable to figure out.
The solution makes use of last_modified_time. However, I am not allowed to use it. I need to use some other mechanism.
What are the options? Is there a possibility of pre-calculating the versions during build and updating(replacing) them in jsps via build script (before deployment, so that the version numbers are not calculated on run time)? Any existing tool for this purpose? I use Java/Jsp.
We always use
file.css?[deploytimestamp]
This way the CSS file is cached for each deployment at the client. The same goes for our minified javascript. Is this an option for you?
It may not be the best way, but this is what I am doing now:
All of my js/css have a [source control = svn] revision number
References in my jsp are like /foo/path1/path2/xyz000000/foo.
Build Step 1 - Generate a map of css|js files and their revision numbers
Build Step 2 - Replace xyz000000 references in jsps with a hash of svn revisions
A rule in url rewriter to direct all /foo/path1/path2/xyz<767678>/foo. to /foo/path1/path2/foo.[js|css]
Infinitely cache the css|js files
Whenever there is a commit, the revision number changes and so do the references in .jsp
Generate an md5-hash of each css file after deployment. Use this hash instead of the timestamp in the url of the css.
file.css?[hash of file.css contents]
It may be wise to calculate the hashes once after deployment and store them to gain some performance. You could store them in a database, or even in a PHP array in a separate file that is included in your website code.

Categories