Comment accéder à l'iframe parent à partir de JavaScript

170

Eh bien, j'ai un IFrame, qui appelle une même page de domaine. Mon problème est que je souhaite accéder à certaines informations de cet Iframe parent à partir de cette page appelée (à partir de JavaScript). Comment puis-je accéder à cet Iframe?

Détails: Il existe plusieurs Iframes comme celui-ci, qui peuvent avoir la même page chargée, car je programme un environnement Windows. J'ai l'intention de fermer cette Iframe, c'est pourquoi j'ai besoin de savoir laquelle je dois fermer de l'intérieur de lui. J'ai un tableau gardant des références à ces Iframes.

EDIT: les iframes sont générés dynamiquement

José Leal
la source
même si les iframes sont générées dynamiquement, vous pouvez attribuer un nouvel identifiant unique en utilisant une sorte de compteur, enfin vous n'avez pas besoin de connaître l'identifiant, mais vous pouvez rechercher facilement, voir ma réponse.
Akash Kava

Réponses:

138

Vous pouvez également définir le nom et l'ID sur des valeurs égales

<iframe id="frame1" name="frame1" src="any.html"></iframe>

vous pourrez donc utiliser le code suivant dans la page enfant

parent.document.getElementById(window.name);
Aquatique
la source
16
Ce n'est peut-être pas évident pour tout le monde, mais avec cette méthode, vous pouvez accéder à un objet bibliothèque du parent (uniquement si le parent a déjà chargé la bibliothèque). Exemple: accéder à jQuery avec le parent. $ ('#
Something
1
Cette solution est compatible avec le mode quirks de compatibilité IE5 +.
Slayner
Même en 2016, cela fonctionne très bien dans le cadre d'une solution au problème de l'impression IE du contenu d'un iframefichier trop petit. Mais pourquoi ça marche? window.namerenvoie une chaîne. Qu'y a-t-il de différent dans l'utilisation window.nameque de simplement passer le nom de l'ID sous forme de chaîne qui ne fonctionne pas.)?
Karl
3
Salut, il ne fonctionne pas avec Chrome 59 ..: VM111: 1 Uncaught DOMException: a bloqué une image avec l'origine « xxx » d'accéder à une image d'origine croisée.
Didier68
Chrome voit les fichiers dans le même dossier que l'origine croisée si CORS n'est pas défini. Ils disent que c'est pour la sécurité. La configuration de CORS nécessite un serveur. Donnez aux utilisateurs un message pour configurer un serveur ou changer de navigateur si Chrome est détecté.
90

Appelez simplement window.frameElementdepuis votre page encadrée. Si la page n'est pas dans un cadre, alors frameElementseranull .

L'autre manière (obtenir l'élément window dans un cadre est moins trivial) mais par souci d'exhaustivité:

/**
 * @param f, iframe or frame element
 * @return Window object inside the given frame
 * @effect will append f to document.body if f not yet part of the DOM
 * @see Window.frameElement
 * @usage myFrame.document = getFramedWindow(myFrame).document;
 */
function getFramedWindow(f)
{
    if(f.parentNode == null)
        f = document.body.appendChild(f);
    var w = (f.contentWindow || f.contentDocument);
    if(w && w.nodeType && w.nodeType==9)
        w = (w.defaultView || w.parentWindow);
    return w;
}
Ian Carter
la source
2
Merci! Fonctionne sur IE 6+, FF et Chrome!
rustyx
11
window.frameElementrenvoie nulllorsque la fenêtre et l'iframe ont des domaines différents, c'est-à-dire la messagerie cross-origin.
Qwerty
@Qwerty avez-vous trouvé une solution?
Ajay Patidar le
@AjayPatidar Je pense que j'ai abandonné. :(
Qwerty
78

Je recommanderais d'utiliser l' API postMessage .

Dans votre iframe, appelez:

window.parent.postMessage({message: 'Hello world'}, 'http://localhost/');

Dans la page où vous incluez l'iframe, vous pouvez écouter des événements comme celui-ci:

window.addEventListener('message', function(event) {
      if(event.origin === 'http://localhost/')
      {
        alert('Received message: ' + event.data.message);
      }
      else
      {
        alert('Origin not allowed!');
      }

    }, false);

D'ailleurs, il est également possible de faire des appels vers d'autres fenêtres, et pas seulement des iframes.

En savoir plus sur l'API postMessage sur le blog John Resigs ici

Kenneth Lynne
la source
7
Je pense que c'est clairement la meilleure réponse, le <iframe>contenu n'a rien à savoir sur le parent et vice versa. Ils n'ont qu'à obéir au simple contrat de message. Impressionnant!
mfeineis
1
Le <iframe> doit toujours connaître le domaine du parent, non?
Homr Zodyssey
1
@HomrZodyssey Le domaine parent n'est disponible que comme mécanisme de sécurité, s'il n'est pas connu, vous pouvez le définir '*'.
Amir Ali Akbari
Utilisation '*'sur les clients. Toutes les autres solutions donnent une erreur sur un navigateur Chrome traitant les fichiers du dossier clients comme n'étant pas de la même origine car un serveur n'est pas configuré. C'est la meilleure et la seule solution: dyn-web.com/tutorials/iframes/postmessage
30

Ancienne question, mais j'ai juste eu ce même problème et j'ai trouvé un moyen d'obtenir l'iframe. Il s'agit simplement d'itérer dans le tableau frames [] de la fenêtre parente et de tester le contentWindow de chaque frame par rapport à la fenêtre dans laquelle votre code s'exécute. Exemple:

var arrFrames = parent.document.getElementsByTagName("IFRAME");
for (var i = 0; i < arrFrames.length; i++) {
  if (arrFrames[i].contentWindow === window) alert("yay!");
}

Ou, en utilisant jQuery:

parent.$("iframe").each(function(iel, el) {
  if(el.contentWindow === window) alert("got it");
});

Cette méthode évite d'attribuer un ID à chaque iframe, ce qui est bien dans votre cas car elles sont créées dynamiquement. Je n'ai pas pu trouver de moyen plus direct, car vous ne pouvez pas obtenir l'élément iframe en utilisant window.parent - il va directement à l'élément de fenêtre parent (en ignorant l'iframe). Les parcourir en boucle semble donc le seul moyen, à moins que vous ne souhaitiez utiliser des identifiants.

ingrédient_15939
la source
1
Mise à jour: cela ne fonctionnait pas exactement comme annoncé, et j'ai dû utiliser le document contentWindow.document ===. Je ne sais pas pourquoi. Également dans certains navigateurs, j'ai utilisé contentDocument. Eh bien, j'aime ça!
Christophe
1
Toutes mes excuses, certes, je ne l'ai testé que dans Firefox. :) Cependant, j'ai eu du succès en utilisant la méthode jQuery et contentWindow dans plusieurs navigateurs.
ingrédient_15939
1
Mise à jour: J'ai découvert que vous pouvez également utiliser window.frameElement, mais je ne sais pas quels navigateurs le prennent en charge.
Christophe
2
Je ne pense pas que ce genre de choses fonctionne plus; vous obtenez une erreur d'origine croisée.
Andrew Mao
@AndrewMao la question porte sur les mêmes documents d'origine, donc aucune raison d'avoir des problèmes d'origine croisée.
Christophe
21

vous pouvez utiliser parentpour accéder à la page parent. Donc, pour accéder à une fonction, ce serait:

var obj = parent.getElementById('foo');
kemiller2002
la source
1
Kevin, le problème est de CONNAÎTRE l'identité. J'ai plusieurs Iframes, et je veux y accéder à partir du code à l'intérieur
José Leal
Toujours obtenir "Bloqué une trame avec l'origine" other-localhost: 8000 "pour accéder à une trame d'origine croisée."
user2568374
13

Une fois que l'identifiant de l'iframe est défini, vous pouvez accéder à l'iframe à partir du document interne comme indiqué ci-dessous.

var iframe = parent.document.getElementById(frameElement.id);

Fonctionne bien dans IE, Chrome et FF.

Akash Kava
la source
Cela semble une façon alambiquée de faire var iframe = frameElement
Oriol
frameElement renvoie l'objet dans le contexte de la fenêtre actuelle, mais parent.document.getElementById (frameElement.id) renvoie l'objet dans le contexte de la fenêtre parente, vous ne pouvez pas exécuter les fonctions javascript de la fenêtre parente avec frameElement, essayez-le dans jsfiddle et donnez-moi un exemple si vous le pouvez .
Akash Kava
6

Peut-être juste utiliser

window.parent

dans votre iframe pour obtenir le cadre / windows appelant. Si vous aviez plusieurs trames d'appel, vous pouvez utiliser

window.top
Clawfire
la source
3

Essayez ceci, dans votre cadre parent, configurez vos IFRAME comme ceci:

<iframe id="frame1" src="inner.html#frame1"></iframe>
<iframe id="frame2" src="inner.html#frame2"></iframe>
<iframe id="frame3" src="inner.html#frame3"></iframe>

Notez que l'id de chaque trame est passé en tant qu'ancre dans le src.

puis dans votre html interne, vous pouvez accéder à l'identifiant du cadre dans lequel il est chargé via location.hash:

<button onclick="alert('I am frame: ' + location.hash.substr(1))">Who Am I?</button>

alors vous pouvez accéder à parent.document.getElementById () pour accéder à la balise iframe depuis l'intérieur de l'iframe

Mark Porter
la source
Oui, ce serait la solution la plus logique, mais parfois j'ai besoin de changer le src de l'iframe .. et en passant ce hachage ou paramètre GET, chaque requête n'est pas bonne ..
José Leal
pourquoi est-il mauvais de passer le hachage à chaque fois? Il n'est visible que par le navigateur, pas par le serveur, et il n'affecte pas la mise en cache comme le ferait un paramètre get.
Mark Porter
-1
// just in case some one is searching for a solution
function get_parent_frame_dom_element(win)
{
    win = (win || window);
    var parentJQuery = window.parent.jQuery;
    var ifrms = parentJQuery("iframe.upload_iframe");
    for (var i = 0; i < ifrms.length; i++)
    {
        if (ifrms[i].contentDocument === win.document)
            return ifrms[i];
    }
    return null;
}
Alex
la source