Is it simple to access the parent iframe from within a window of an iframe?

Recently, I decided to experiment with postMessage in order to deepen my understanding of its functionality. This led me to create the following example:

This experiment involves a slightly complex setup: I created an iframe for every character in a message, each sourced to . Using postMessage, I am able to communicate individually with each iframe to specify which character to display. Additionally, the iframes send information about their geometry back to the parent page via postMessage. While this test page may seem pointless, it serves as a fun experiment.

One challenge I encountered is determining the owning iframe when given an iframe window.

Currently, I am using a for loop to iterate through all my iframes and check the window using ===, but this method feels somewhat inefficient. Are there more efficient ways to accomplish this task?

Answer №1

Unfortunately, there isn't any solution available at the moment. (I don't have much advice to offer other than recognizing that you are already putting in your best efforts.)

Answer №2

One effective approach I propose is to assign a unique identifier to each iframe randomly. During any communication between the iframe and its parent window, the iframe should include its individual identifier in the content of a postMessage. This method enables the parent window to quickly and easily identify the source of incoming messages.

Below is an updated example where the contents of hello-iframe.html are:

<html>
<script src="http://ajax.googleapis.com/ajax/libs/jquery/1.7.1/jquery.min.js"></script>
<script>

var exec = function() {
    var message = "Hello world, this is a test of the emergency broadcast system.";
    var index;
    document.body.appendChild(document.createElement("hr"));
    for (index = 0; index < message.length; index++) {
        createCharacterIframe(message.charAt(index));
    }
    document.body.appendChild(document.createElement("hr"));
};

var _gensymCounter = 0;
var gensym = function() {
    var output = [], index;
    var LENGTH = 32;
    output.push((_gensymCounter++) + "_");
    var characters = "0123456789ABCDEFGHIJKLMNOPQRSTUVWXTZabcdefghiklmnopqrstuvwxyz";
    for (index = 0; index < LENGTH; index++) {
        output.push(characters.charAt(Math.floor(Math.random() * characters.length)));
    }
    return output.join('');
};

var createCharacterIframe = function(ch, id) {
    id = id || gensym();
    var newIframe = document.createElement("iframe");
    newIframe.setAttribute("frameborder", "0");
    newIframe.setAttribute("border", "0px");
    newIframe.setAttribute("width", "0px");
    newIframe.setAttribute("height", "0px");
    newIframe.setAttribute("src", "hello-iframe-inner.html?selfId=" + encodeURIComponent(id));
    newIframe.setAttribute("id", id);
    $(newIframe).data('ch', ch);
    document.body.appendChild(newIframe);
};

var locateIframe = function(w) {
    var located;
    $('iframe').each(function() {
        if (this.contentWindow == w) {
            located = this;
        }  
    });
    return located;
};

$(window).on('message',
             function(e) {
                 var data = e.originalEvent.data;
                 var source = e.originalEvent.source;
                 var iframe, sourceId;

                 if(data.match(/^([^,]+)[,](.+)$/)) {
                     sourceId = RegExp.$1;
                     data = RegExp.$2;
                     if (document.getElementById(sourceId)) {
                         iframe = document.getElementById(sourceId);
                     } else {
                         return;
                     }
                 } else {
                     return;
                 }

                 if (data === 'ready') {
                     iframe.contentWindow.postMessage($(iframe).data('ch'), '*');
                 } else if (data.match(/^(\d+),(\d+)$/)) {
                     var w = RegExp.$1;
                     var h = RegExp.$2;
                     if (iframe.width !== w + 'px') {
                         iframe.width = w + "px";
                     }
                     if (iframe.height !== h + 'px') {
                         iframe.height = h + "px";
                     }
                 }
             });

$(document).ready(exec);

</script>
<body>
<h1>testing iframes</h1>
</body>
</html>

and the content of hello-iframe-inner.html as follows:

<html><head></head>
<script>

// http://stackoverflow.com/questions/901115/get-query-string-values-in-javascript
var urlParams = {};
(function () {
    var e,
        a = /\+/g,
        r = /([^&=]+)=?([^&]*)/g,
        d = function (s) { return decodeURIComponent(s.replace(a, " ")); },
        q = window.location.search.substring(1);

    while (e = r.exec(q))
       urlParams[d(e[1])] = d(e[2]);
})();

var SELF_ID = urlParams.selfId;
window.addEventListener("message",
         function(e) {
             if (e.data === ' ') {
                 document.body.innerHTML = "&nbsp;";
             } else {
                 document.body.appendChild(
                     document.createTextNode(e.data));
             }
         });

window.onload = function() {
    document.body.style.margin = '0px';
    var width, height;
    if (window.parent && SELF_ID) {
        window.parent.postMessage(SELF_ID + ',ready', '*');

        setInterval(function() {
            if (height !== document.body.scrollHeight ||
                width !== document.body.scrollWidth) {
                width = document.body.scrollWidth;
                height = document.body.scrollHeight;
                if (window.parent) {
                    window.parent.postMessage(SELF_ID + ',' + width + ',' + height, '*');
                }
            }
        }, 1000);
    }
};
</script>
<body></body>
</html>

Similar questions

If you have not found the answer to your question or you are interested in this topic, then look at other similar questions below or use the search

Vue: The computed property cannot be set

I'm having trouble with utilizing computed properties and ajax calls in Vue.js. The "filterFactories" variable stores a list of factories. A computed property named "filterFactories" generates this list of factories. Now, I am looking to implement a ...

Highlight the active menu item using jQuery

Check out my menu example here: http://jsfiddle.net/hu5x3hL1/3/ Here is the HTML code: <ul id="menu" class="sidebar"> <li> <a href="#" class="clickme">Menu</a> <ul id="menu1"> <li><a class="dropdown-clas ...

Issues loading Static files with Django

I tried to load static files such as CSS and JavaScript using the Django static tag, but encountered some issues. Most of the JavaScript files are not working and some CSS files are also not being loaded. Error message for all JavaScript: The script fr ...

Safely displaying a JavaScript escaped string in PHP output

When taking user inputs safely using encodeURIComponent() (and encodeURI() for e-mails) and sending them to PHP via AJAX, I escape the output and store it in a $_SESSION[] which is later echoed. I am looking for a way to print this to HTML normally without ...

What is the best way to send a request in a route and wait to return a response until the data is ready?

I've been advised to utilize axios for making API requests, but I'm encountering the issue of it being asynchronous and responding before the inner POST request is fully completed: var express = require('express'); const axios = require ...

Unique patterns on a 3D model in Three.js

I am attempting to replicate the look of the model shown in this photo https://i.sstatic.net/IDLaV.png How can I remove the strange lines from the model while rotating it? You can observe these lines when rotating the model on this link . What seems to be ...

Multi selection dropdown feature in Angular failing to populate the options

I am working on a small Angular controller that manages a dropdown menu, with the second dropdown menu populating based on the selection made in the first one. Despite my best efforts, I can't seem to populate the dropdown menus with any content from ...

Successful AJAX Post request functioning exclusively within the Web Console (Preview)

When a user clicks on an element on the website, I have a simple AJAX request to send the ID of that element. However, the script only works in the Web Console under the Network -> Preview section and this issue occurs across all browsers. Here is the ...

Error: The function 'drawImage' on 'CanvasRenderingContext2D' could not be executed due to the HTMLImageElement being in a 'corrupted' state

import { Bodies, Composite, Engine, Mouse, MouseConstraint, Render, Runner } from 'matter-js'; import React, { useEffect } from 'react'; import * as S from './styles'; import flutter from '../../../../public/Icon/flutterL ...

multiple event listeners combined into a single function

I'm looking to streamline my button handling in JavaScript by creating just one function that can handle all the buttons on my page. Each button will trigger a different action, so I need a way to differentiate between them. I thought of using one eve ...

The filtering function stops working after the initial use

As I develop an app using React and Redux, my goal for the following code snippet is to function as a reducer within the main application. I have imported a filterData function, which works seamlessly the first time any Action type is selected. However, it ...

Stop clicks from interfering with dragging in three.js

My GLTF model in Three.js has objects within it, and I want the camera to zoom in on an object when the user clicks on it. However, I am facing an issue where if the user drags after clicking on an object, a click is triggered upon releasing the mouse butt ...

Transfering external store information to PHP

I am currently working with an EditorGridPanel on my webpage. My aim is to send the updated data to PHP using the POST method, but only after the Save Button is clicked. I am aware that I can convert the data to an array and send it like a form, but I am c ...

Can HTML5 and JavaScript be used to clip a portion of a video and upload it directly to a server?

Currently, I am using Filereader to read a local video file (mp4) in order to display it in a video tag. However, I am looking to cut a specific part of the mp4 file (for example, from 5 to 10 seconds) and then upload it to a server. My current approach: ...

Tips for effectively removing a MathLive.makeMathField object

When I set up a field for editing within a modal window, my goal is to properly remove an instance of MathLive once the modal is closed. mounted() { mathField = MathLive.makeMathField(this.$refs.mathField, { virtualKeyboardMode: 'manual&a ...

Finding the best way to transfer text between DIV elements?

I have a dilemma involving two DIV elements positioned absolutely on the sides of an HTML page, much like this EXAMPLE: <div class="left"> </div> <div class="right"> </div> These are styled using the following CSS: .left{ pos ...

What steps can I take to implement automation for this traffic light sequence?

document.getElementById('SwitchButton').onclick = automateLights; function turnOnRedLight() { clearAllLights(); document.getElementById('stopLight').style.backgroundColor = "red"; } function turnOnOrangeLight() { clearAllLights( ...

Steps for dynamically adjusting form fields depending on radio button selection

I am looking to create a dynamic form that changes based on the selection of radio buttons. The form includes textfields Field A, Field B, ..., Field G, along with radio buttons Radio 1 and Radio 2. I need to update the form dynamically depending on which ...

Tips for executing a sequence of actions following a successful data retrieval in JavaScript

let users_data = []; try { let users = await chatModel.find({ users: isVerified.userId }); users.forEach(function (doc) { doc.users.forEach(async function (user) { if (isVerified.userId !== user) { let result = await userModel.find({ ...

Creating a mandatory and meaningful text input in Angular 2 is essential for a

I am trying to ensure that a text material input in my app is mandatory, with a message like "Please enter issue description." However, I have noticed that users can bypass this by entering spaces or meaningless characters like "xxx." Is there an npm pac ...