web-dev-qa-db-fra.com

Pourquoi iframe.contentWindow == null?

J'utilise le code suivant pour créer dynamiquement un iframe.

var iframe_jquery = $("<iframe>")
    .addClass("foo")
    .appendTo(container); // container is a jQuery object containing a <div> which already exists

Ensuite, je veux accéder à son contentWindow, mais c'est nul:

var iframe = iframe_jquery.get(0);
if (iframe){ // iFrame exists
    console.log(iframe.contentWindow); // Prints "null"
    var doc = iframe.contentWindow.document; // NullpointerException
}

Alors j'ai pensé: "Peut-être que l'iframe n'est pas encore prêt?" J'ai donc essayé:

iframe_jquery.ready(function(){
    var iframe = iframe_jquery.get(0);
    console.log(iframe.contentWindow); // Prints "null"
    var doc = iframe.contentWindow.document; // NullpointerException
});

Même résultat.

Qu'est-ce qui ne va pas?

43
Timo

J'ai eu ce problème la semaine dernière en jouant avec des iFrames (construction d'un éditeur rtf), et oui ce n'est pas encore prêt.

Je pensais que si je le mettais dans une .ready() ça marcherait, mais .ready() c'est quand le DOM est prêt, pas quand l'iFrame a chargé son contenu, donc j'ai fini par envelopper mon code avec jQuery .load().

Essayez donc ceci:

$(function () {  
    $("#myiframe").load(function () {                        
        frames["myframe"].document.body.innerHTML = htmlValue;
    });
}); 

J'espère que cela t'aides

35
Losbear

Le problème est que votre <iframe> ne sera pas "réel" tant qu'il ne sera pas vraiment ajouté au DOM réel de la page. Voici un violon à démontrer. .

14
Pointy

Selon le navigateur, accéder à document ou à <iframe> peut varier.

Voici un exemple de la façon de le gérer:

if (iframe.contentDocument) // FF Chrome
  doc = iframe.contentDocument;
else if ( iframe.contentWindow ) // IE
  doc = iframe.contentWindow.document;
6
Gabe

Version du Bookmarklet

Par simple curiosité, j'ai pensé que j'allais mettre ça ensemble. Se souvenir que les iframes et les événements de chargement ne fonctionnent pas bien ensemble sur différents navigateurs (principalement les plus anciens, en train de s'effondrer, les navigateurs devraient être morts) ... en plus de ne pas être entièrement sûr de la façon dont jQuery contourne ce problème ... mon cerveau a décidé que ce serait mieux pris en charge (que ce soit ou non n'est ni ici ni là):

$(function(){
  /// bind a listener for the bespoke iframeload event
  $(window).bind('iframeload', function(){
    /// access the contents of the iframe using jQuery notation
    iframe.show().contents().find('body').html('hello');
  });
  /// create your iframe
  var iframe = $('<iframe />')
        /// by forcing our iframe to evaluate javascript in the path, we know when it's ready
        .attr('src', 'javascript:(function(){try{p=window.parent;p.jQuery(p).trigger(\'iframeload\');}catch(ee){};})();')
        /// insert the iframe into the live DOM
        .appendTo('body');
});

La raison de cette approche est qu'il est généralement préférable de déclencher votre événement de chargement depuis l'iframe lui-même. Mais cela signifie avoir un bon document chargé dans l'iframe, donc pour les iframes dynamiques, c'est un peu fastidieux. C'est une sorte de mélange entre le chargement d'un document et non.

Ce qui précède fonctionne sur tout ce que j'ai testé jusqu'à présent - et oui, vous avez raison - c'est un peu ridicule, non pérenne et probablement d'autres choses qui ont des connotations négatives;)

Une chose positive que je dirai à propos de cet article est qu'il introduit l'utilisation de .contents() pour accéder au document de l'iframe, ce qui est au moins un peu utile ...

2
Pebbl

Vous pouvez également créer une fonction qui sera exécutée lorsque l'iframe aura fini de se charger en définissant son attribut onload.

1
Vladivarius