Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

DOMContentLoaded event not firing

I'm trying to detect when the DOM is ready using DOMContentLoaded.

I'm injecting the following JavaScript code into a page:

var script = document.createElement('script');  
script.type = 'text/javascript';  
script.text = function addListener() {
    if (document.addEventListener) {
        document.addEventListener("DOMContentLoaded", DOMReady, false);
    }
};

function DOMReady() {
    document.location.href = "mydomain://anything.stuff";
}

function inject() {
    document.getElementsByTagName('head')[0].appendChild(script);
    addListener();
}

It gets added by:

-(void)webViewDidFinishLoad:(UIWebView *)webView
{
    static BOOL injected = NO;
    if (!injected)
    {
        NSBundle *bundle = [NSBundle mainBundle];
        NSURL *jsURL = [bundle URLForResource:@"DetectDOMLoaded" withExtension:@"js"];  
        NSData *jsData = [NSData dataWithContentsOfURL:jsURL];
        NSString *jsScriptAsString = [[NSMutableString alloc] initWithData:jsData encoding:NSUTF8StringEncoding];
        [self.webView stringByEvaluatingJavaScriptFromString:jsScriptAsString];
        [self.webView stringByEvaluatingJavaScriptFromString:@"inject();"];
        injected = YES;
    }

If I add alert calls I can see that the call to addEventListener is being successfully made. However the function DOMReady() is never called. Any ideas why not?

Thanks

like image 563
Gruntcakes Avatar asked Mar 15 '12 15:03

Gruntcakes


1 Answers

The reason is that you inject the javascript in the webViewDidFinishLoad: method. That method is called after the UIWebLoad has loaded the HTML page. Meaning that the DOMContentLoaded event may already have been fired, before your javascript has been injected.

I see two possiblities how to fix this problem:

  1. If you have access to the HTML that you are loading into the UIWebView, insert the javascript directly into the HTML. That guarantees that the javascript is already there when DOMContentLoaded is being fired.

  2. If you don't have access to the HTML, you could call your DOMReady() JS function directly from the webViewDidFinishLoad: method (like you call inject() now). The DOM will be fully loaded at that point. The only insecurity with this option is, that the DOM will be fully loaded but might not yet be fully rendered. So if you need the size of certain DOM elements, this option is not secure (because the elements might not have been rendered at that point). But if you are just doing something that does not rely on the DOM being fully rendered, this option should be fine.

like image 165
joern Avatar answered Sep 29 '22 16:09

joern