I'm trying to append an iframe
element into document.body
as soon as possible.
Error reports are coming in across all 4 major browsers (Chrome, Safari, FF, IE --various versions), we see document.body
is null
. I think this happens when my JS file is cached and loads quickly.
Here is the logic to insert the iframe
:
private loadIFrame(): void {
switch (document.readyState) {
case 'uninitialized':
case 'loading':
case 'loaded':
window.addEventListener('DOMContentLoaded',
this.appendIFrame.bind(this)
)
break
case 'interactive':
case 'complete':
default:
this.appendIFrame()
}
}
private appendIFrame(): void {
if (document.getElementById('iframeId')) {
return
}
let iFrame: HTMLIFrameElement = document.createElement('iframe')
iFrame.src = document.location.protocol + this.ORIGIN + '/iframe.html'
iFrame.id = 'iframeId'
// document.body is null here
document.body.appendChild(iFrame)
}
I'm having a hard time reproducing the issue in a clean environment, which leaves me guessing how this happens out in the wild.
I originally tried this rreadyState
logic, but we saw document.body
was undefined
in IE when in the loading
state.
private loadIFrame(): void {
switch (document.readyState) {
case 'uninitialized':
case 'loading':
window.addEventListener('DOMContentLoaded',
this.appendIFrame.bind(this)
)
break
case 'loaded':
case 'interactive':
case 'complete':
default:
this.appendIFrame()
}
}
My current line of questioning....
default
case? Should I add the event listener there? I could modify the order of the cases so that the event listener is default?body
is null
on the DOMContentLoaded
event?document.readyState
that are falling through?I updated the logic, and I was able to almost eliminate the errors, but I am still seeing document.body
is null
when readyState
is interactive
.
I'll be updating this post once I assess the specific browser scenarios that cause the issue.
private loadIFrame(): void {
switch (document.readyState) {
case 'uninitialized':
case 'loading':
case 'loaded':
document.addEventListener('DOMContentLoaded',
this.appendIFrame.bind(this)
)
break
case 'interactive':
case 'complete':
default:
if(document.body) {
this.appendIFrame()
} else {
window.addEventListener('load',
this.appendIFrame.bind(this)
)
}
}
}