Hello fellow problem solvers! I'm hoping to learn something from you. I ran into a challenge that could probably teach me more about Angular, and I would appreciate any input anyone might have.
Background
My company shares a common footer among many web sites, and we lazy-load that into each site using JSONP. The footer content is managed by a system that generates static HTML, for high performance, low costs, and high uptime. When we lazy-load that footer into pages, we cannot control the name of the callback function call included in the response.
Our footer might look something like this footer.json file:
footerCallback(["<footer>FROM THE FOOTER</footer>"]);
We lazy-load that into HTML pages with simple pure-Javascript code like this:
<div id="footer"></div>
<script>
function footerCallback(json_data){
document.getElementById('footer').outerHTML = json_data[0];
}
window.onload = function() {
var script = document.createElement('script');
script.src = 'assets/static-footer.json'
script.async = true;
document.getElementsByTagName('head')[0].appendChild(script);
}
</script>
I posted a working demo on GitHub, here. Unfortunately I couldn't post it on Stackblitz to make it easier to run, since it uses JSONP requests. This version includes the shared footer in exactly the way that I described above, right here.
Challenge
We need to include that same central footer in Angluar apps, so I'm trying to create a footer component that will insert that lazy-loaded JSONP footer into an Angular app.
Approach
I created a footer component and a footer service, and I'm using HttpClientJsonpModule to do a JSONP request. That part works. The service sends the JSONP request and I can see the response in my inspector in Chrome.
Problem
The part that does not work is the callback. I can't remove the original global callback function from the main index.html because I don't know how to replace it with a function that the JSONP response can trigger. I was able to move the callback function into the component, but only by continuing to define it globally:
function footerCallback(json_data){
document.getElementById('footer').outerHTML = json_data[0];
}
const _global = (window) as any
_global.footerCallback = footerCallback
Angular expects to be able to tell the JSONP server the name of the callback function to include in the JSONP response. But there is no server, it's just a static file.
Angular is flexible enough that I can tell it the URL parameter to use to specify that callback function. If I specify "callback" as the callback function name with this.http.jsonp(this.footerURL,'callback') then it will issue a request like this:
https://...footer.min.json?callback=ng_jsonp_callback_0
That's a nice feature and all, but it's the ng_jsonp_callback_0 that I need to customize, not the URL parameter. Because the server cannot adjust its response to include a reference to the function ng_jsonp_callback_0. Because there is no server, it's just a static file.
Ugly solution
My workaround was to define the callback function in the global scope. That way, I can support whatever callback function names the API or static file requires.
This at least enables me to encapsulate everything related to the lazy-loading footer into a footer component with its own service. But I feel like I'm not really doing this in the Angular Way, if I'm polluting the global scope.
Question
Is there a way for me to manually specify the name of that callback function myself, rather than letting Angular pick the name ng_jsonp_callback_0 or whatever?
If not, then is there some other elegant way to handle this? Other than using a global callback function?