0

I want to inject a whole html page into a "main" page. I succeeded in doing this, but I still need to access variables of the injected page, from within the main page. Here is an example:

I have my index page, where I injected a GIS page.

I want to access the map variable (created in "gis.html") from within my index page, in order to control my GIS app from the main (index) page.

index.html

<html>
    <head>
        <title>Index</title>
        <meta charset="UTF-8">
        <meta name="viewport" content="width=device-width">
        <style>
            #menu {height: 50px;}
            #gisContainer {margin-left: 50px;}
        </style>
    </head>
    <body>
        <div id="menu">
            <button id="zoomOut" onclick="zoomOut()">ZOOM OUT</button>
            <button id="zoomIn" onclick="zoomIn()">ZOOM IN</button>
        </div>
        <div id="gisContainer"></div>
        <script>
            function getZoom() {
                return map.getView().getZoom();
            }
            function zoomOut() {
                map.getView().setZoom(getZoom() - 1);
            }
            function zoomIn() {
                map.getView().setZoom(getZoom() + 1);
            }
            var url = 'http://qwaserdf.esy.es/gis.html';
            var objectTag = '<object id="gisObj" width="1000" height="600" data="'
                                + url + '" type="text/html">'
                                + '<embed src="' + url + '" type="text/html" />'
                            + '</object>';
            document.getElementById('gisContainer').innerHTML = objectTag;
        </script>
    </body>
</html>

gis.html

<html>
    <head>
        <title>GIS</title>
        <meta charset="UTF-8">
        <meta name="viewport" content="width=device-width">
        <link rel="shortcut icon" href="#">
        <script src="https://code.jquery.com/jquery-3.1.0.min.js" type="text/javascript"></script>
        <script src="https://cdnjs.cloudflare.com/ajax/libs/ol3/3.16.0/ol.js" type="text/javascript"></script>
        <link href="https://cdnjs.cloudflare.com/ajax/libs/ol3/3.16.0/ol.css" rel="stylesheet" type="text/css">
        <style>
            html, body {height: 100%; width: 100%; padding: 0; margin: 0; border: 0;}
            .map {height: 100%; width: 100%;}
        </style>
    </head>
    <body>
        <div id="map" class="map"></div>
        <script>
            var map = new ol.Map({
                target: 'map',
                layers: [
                    new ol.layer.Tile({
                        source: new ol.source.OSM()
                    })
                ],
                view: new ol.View({
                    center: [-603463.751013, 4952779.63173],
                    zoom: 5
                })
            });
        </script>
    </body>
</html>

Here are the pages that I am talking about:

EDIT 1: DIFFERENT DOMAINS ---> IMPORTANT

The two html pages are supposed to be on different domains. For example, "gis.html" is the GIS Web App that I developed. The "index.html" would be a webpage of a client that wants to integrate a small web app on his site.

1

Given that both your HTML sites are hosted on the same domain (due to CORS) you can access the map object via window.frames[0].map. However, if you add other object elements on your page, you might have to guess their index number, I'm not sure if they will stay in order.

A slightly better way is to use actual iframe elements which can be referenced by name:

var frameTag = document.createElement("iframe");
frameTag.setAttribute("id", "myMap");
frameTag.setAttribute("src", url);
frameTag.setAttribute("style", "width: 1000px; height: 600px; border: none;");

frameTag.addEventListener("load", function() {
  // wait for the frame to load, otherwise "map" is "undefined"
  map = window.frames["myMap"].contentWindow.map
  // if you want to use <object>:
  // map = window.frames[0].map
});

var gisContainer = document.getElementById("gisContainer");
gisContainer.appendChild(frameTag);

Here's a demo: https://plnkr.co/edit/FR39Mroa3wsfpcwf4b0P?p=preview


If your websites are not on the same domain name you can use Window.postMessage() to send messages between them.

To send a message use:

window.frames["myMap"].contentWindow.postMessage("zoomOut", "https://example.com")

"zoomOut" is the message to be sent, you might also send more elaborate objects with more parameters (likewise, you need to parse them on the receiving side):

window.frames["myMap"].contentWindow.postMessage({"action": "zoomIn", "steps": 3}, "https://example.com")

example.com is where the receiving site is hosted, it's a good idea to restrict these to fixed domains instead of using the wilcard "*" for security reasons (you might retrieve arbitrary Javascript code from other domains, which can pose a security risk). Same goes for the site retrieving these messages.

On the receiving site use addEventListener to listen for message events:

window.addEventListener("message", function(event){
  // check where the request came from
  var origin = event.origin || event.originalEvent.origin;
  if (origin !== "https://example.com"){
    console.log("Denied for origin", origin)
    return;
  }

  if(event.data === "zoomIn") {
    zoomIn()
  }
  if(event.data === "zoomOut") {
    zoomOut()
  }
  // when you are sending and receiving objects instead:
  //if(event.data.action && event.data.action === "zoomOut") {
  //  zoomOut()
  //}
}, false);

Here example.com is where the message came from, you might also provide a list of domains by using an array and indexOf().

Example for postMessage() usage: https://plnkr.co/edit/OB4DEAMtIhGglM2zcXut?p=preview

  • Thank you very much. But, what if the two sites are NOT on the same domain? (I should have explained that in the post. They are supposed to be on different domains.) – joaorodr84 Aug 5 '16 at 19:27
  • 1
    @joaorodr84 Are all the domains under your control? There is a way to do this with Window.postMessage(), but it's more complicated and you are not able to directly access the map object, you will have to change the code on the object site. I will edit my post – chrki Aug 5 '16 at 19:30
  • No, the domain of "gis.html" would be mine. But the domain of "index.html" would belong to a client that wants to use my GIS Web App. (I edited my question) – joaorodr84 Aug 5 '16 at 19:32
  • 1
    @joaorodr84 I edited it – chrki Aug 5 '16 at 20:03
  • Thanks. I will try this out and I will give some more feedback after that. :) – joaorodr84 Aug 5 '16 at 20:06

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service, privacy policy and cookie policy

Not the answer you're looking for? Browse other questions tagged or ask your own question.