328

I want to call a parent window JavaScript function from an iframe.

<script>
    function abc()
    {
        alert("sss");
    }
</script>

<iframe id="myFrame">
    <a onclick="abc();" href="#">Call Me</a>
</iframe>
Diptendu
  • 2,120
  • 1
  • 15
  • 28
Arjun Singh
  • 3,291
  • 2
  • 16
  • 6

11 Answers11

490
<a onclick="parent.abc();" href="#" >Call Me </a>

See window.parent

Returns a reference to the parent of the current window or subframe.

If a window does not have a parent, its parent property is a reference to itself.

When a window is loaded in an <iframe>, <object>, or <frame>, its parent is the window with the element embedding the window.

Zaheer Ahmed
  • 28,160
  • 11
  • 74
  • 110
rahul
  • 184,426
  • 49
  • 232
  • 263
  • 27
    Always take into account that parent document and iframe document must match by protocol and domain name. If it does not happen then you will get a security error as it is not allow to have cross domain scripting. – a4bike Sep 02 '15 at 16:08
  • M just wondering which one the two `alert`s will be invoked; parent's `alert` function or iframe's `alert` function, in case `parent.abc();` is called on iframe? – Prakhar Mishra Mar 03 '16 at 11:33
  • @PrakharMishra Don't be confused. parent means parent. – Vishal Kumar Sahu Mar 16 '17 at 10:02
  • 4
    @a4bike for such scenarios, `window.postMessage()` (or `window.parent.postMessage()`) exists. Check [@Andrii answer](http://stackoverflow.com/a/41566923/1369473) – Fr0zenFyr May 06 '17 at 05:35
133

Window.postMessage()

This method safely enables cross-origin communication.

And if you have access to parent page code then any parent method can be called as well as any data can be passed directly from Iframe. Here is a small example:

Parent page:

if (window.addEventListener) {
    window.addEventListener("message", onMessage, false);        
} 
else if (window.attachEvent) {
    window.attachEvent("onmessage", onMessage, false);
}

function onMessage(event) {
    // Check sender origin to be trusted
    if (event.origin !== "http://example.com") return;

    var data = event.data;

    if (typeof(window[data.func]) == "function") {
        window[data.func].call(null, data.message);
    }
}

// Function to be called from iframe
function parentFunc(message) {
    alert(message);
}

Iframe code:

window.parent.postMessage({
    'func': 'parentFunc',
    'message': 'Message text from iframe.'
}, "*");
// Use target origin instead of *

UPDATES:

Security note:

Always provide a specific targetOrigin, NOT *, if you know where the other window's document should be located. Failing to provide a specific target discloses the data you send to any interested malicious site (comment by ZalemCitizen).

References:

Andrii Verbytskyi
  • 7,155
  • 3
  • 47
  • 38
  • 2
    I prefer using this over others. Especially because it makes more sense to use iframes on cross origin docs (although programmers do exploit iframes more often than not) and given the wide support for this function on browsers. – Fr0zenFyr May 06 '17 at 05:31
  • 3
    Thanks! I always have to spend an hour or more going back and researching how to do the messaging with over complicated,verbose examples. This worked in 60 seconds. Thanks for an example that is succinct and to the point. – RandallTo Jan 17 '19 at 18:26
  • 3
    worth to raise that (from [MDN web docs](https://developer.mozilla.org/en-US/docs/Web/API/Window/postMessage)) : Always provide a specific targetOrigin, not *, if you know where the other window's document should be located. Failing to provide a specific target discloses the data you send to any interested malicious site – ZalemCitizen Mar 25 '19 at 09:45
  • 1
    i like this approach, the answer is clear and concise – Alexander Sep 09 '20 at 03:10
  • how do I attach the iframe code to the iframe? do I have to modify the iframe site's html? or can I inject it from the parent page? – oldpride Sep 11 '22 at 16:35
86

I recently had to find out why this didn't work too.

The javascript you want to call from the child iframe needs to be in the head of the parent. If it is in the body, the script is not available in the global scope.

<head>
    <script>
    function abc() {
        alert("sss");
    }
    </script>
</head>
<body>
    <iframe id="myFrame">
        <a onclick="parent.abc();" href="#">Click Me</a>
    </iframe>
</body>

Hope this helps anyone that stumbles upon this issue again.

Ash Clarke
  • 4,807
  • 1
  • 37
  • 48
  • 2
    None of the techniques mentioned in this post work on Chrome. Any solutions for this? – Kumar Kush Jan 05 '12 at 10:48
  • 4
    If I remember correctly, I couldn't get this to work as expected if the iframe had a different domain to the parent. Sorry this isn't a solution, but it might explain why it isn't working. – Ash Clarke Jan 09 '12 at 09:34
  • 1
    Yes. I do know that it is because of different domains, but is there not a way to work this around? – Kumar Kush Jan 09 '12 at 18:15
  • 1
    I have just posted what might be a workaround to your problem. Take a look at the other answer. – Ash Clarke Feb 20 '12 at 10:01
  • So I have a domain something.com and my iframe is at something.something.com and I get a permission denied error. Shouldn't a subdomain be able to work? – Caimen Jun 26 '14 at 21:17
  • 1
    As per the same origin policy determination rules (see: http://en.wikipedia.org/wiki/Same-origin_policy#Origin_determination_rules), subdomains are considered a different hostname to a subdomain of a domain. If you haven't already, you could try just setting document.domain to the subdomain? – Ash Clarke Jun 27 '14 at 11:14
  • M just wondering which one the two `alert`s will be invoked; parent's `alert` function or iframe's `alert` function, in case `parent.abc();` is called on iframe? – Prakhar Mishra Mar 03 '16 at 11:24
  • I had no problems calling the script in the body (not the head). Of course, it is 5 years after the answer, so things may have changed. Also, I was from the same domain. – Guy Schalnat Sep 07 '16 at 16:50
  • It has nothing do with being in the body vs being in the head. It has to with being defined before being used. You can put your script in the body just fine. You can even put it at the end. You just need to make sure it's not called from the child until it's defined in the parent. One way to do that is to put the script in the head of the parent but there are many other ways. – gman May 15 '19 at 05:51
19

You can use

window.top

see the following.

<head>
    <script>
    function abc() {
        alert("sss");
    }
    </script>
</head>
<body>
    <iframe id="myFrame">
        <a onclick="window.top.abc();" href="#">Click Me</a>
    </iframe>
</body>
Vinothkumar Arputharaj
  • 4,567
  • 4
  • 29
  • 36
  • 2
    When trying to call parent.custom_function(); from an iframe does not work you may find window.top.custom_function(); will work. Works for me for some odd reason. My javascripts on the parent window are all embedded in the footer, i read somewhere that including javascript files in the footer causes the problem parent.custom_function() is not working. – Friso Horstman May 18 '16 at 16:55
  • @Vinothkumar, one question please, which is the difference between calling "window.top.abc()" than calling only "abc()" , thanks in advance =) – Zilev av Jun 30 '16 at 22:37
  • @Zilev av The entire point of this thread is calling a function in a parent document from a child iframe. That's the difference. Calling `abc()` would only work if `function abc()` were declared *in the iframe* as opposed to on the parent page. `window.top.abc()` breaks out of the iframe into the parent document. – Sean Kendle Aug 12 '16 at 16:27
19

I have posted this as a separate answer as it is unrelated to my existing answer.

This issue recently cropped up again for accessing a parent from an iframe referencing a subdomain and the existing fixes did not work.

This time the answer was to modify the document.domain of the parent page and the iframe to be the same. This will fool the same origin policy checks into thinking they co-exist on exactly the same domain (subdomains are considered a different host and fail the same origin policy check).

Insert the following to the <head> of the page in the iframe to match the parent domain (adjust for your doctype).

<script>
    document.domain = "mydomain.com";
</script>

Please note that this will throw an error on localhost development, so use a check like the following to avoid the error:

if (!window.location.href.match(/localhost/gi)) {
    document.domain = "mydomain.com";
} 
Ash Clarke
  • 4,807
  • 1
  • 37
  • 48
  • and what about testing this in localhost? any workaround for that? – Umesh Awasthi Jun 19 '12 at 17:09
  • See: "Please note that this will throw an error on localhost development, so use a check like the following to avoid the error" – Ash Clarke Jun 27 '12 at 10:51
  • 2
    It is worth noting that (at least in Google Chrome) both, parent and child MUST SET document.domain even if one of them is already "correct"! Example: Parent is `example.com` iframe is `abc.example.com`, then both parent and iframe must call `document.domain = "example.com"` – KillerX Aug 08 '12 at 09:49
  • Yes that is correct, I made a typo here: "page in the iframe to be the same." should be "page and the iframe to be the same." ..... Thanks! – Ash Clarke Aug 08 '12 at 13:39
  • for the if() why wouldn't you just use if(document.domain != "mydomain.com" ? Also, I'm confused, does the – user2568374 May 15 '18 at 12:32
4

parent.abc() will only work on same domain due to security purposes. i tried this workaround and mine worked perfectly.

<head>
    <script>
    function abc() {
        alert("sss");
    }

    // window of the iframe
    var innerWindow = document.getElementById('myFrame').contentWindow;
    innerWindow.abc= abc;

    </script>
</head>
<body>
    <iframe id="myFrame">
        <a onclick="abc();" href="#">Click Me</a>
    </iframe>
</body>

Hope this helps. :)

Seph Remotigue
  • 427
  • 1
  • 3
  • 9
  • This is also really only any use for the iframe's document, adding massive complications if you need to refer to controls on the parent form. – Paul Dec 08 '16 at 11:29
  • Sweet trick but didnt work for me using an iframe in a chrome extension context. :( – johnw182 Sep 20 '22 at 15:53
3

Another addition for those who need it. Ash Clarke's solution does not work if they are using different protocols so be sure that if you are using SSL, your iframe is using SSL as well or it will break the function. His solution did work for the domains itself though, so thanks for that.

Devon Bessemer
  • 34,461
  • 9
  • 69
  • 95
2

The solution given by Ash Clarke for subdomains works great, but please note that you need to include the document.domain = "mydomain.com"; in both the head of the iframe page and the head of the parent page, as stated in the link same origin policy checks

An important extension to the same origin policy implemented for JavaScript DOM access (but not for most of the other flavors of same-origin checks) is that two sites sharing a common top-level domain may opt to communicate despite failing the "same host" check by mutually setting their respective document.domain DOM property to the same qualified, right-hand fragment of their current host name. For example, if http://en.example.com/ and http://fr.example.com/ both set document.domain to "example.com", they would be from that point on considered same-origin for the purpose of DOM manipulation.

Frato
  • 476
  • 5
  • 4
  • Yes that is correct, I made a typo here: "page in the iframe to be the same." should be "page and the iframe to be the same." ..... Thanks! – Ash Clarke Aug 08 '12 at 13:40
  • how about running files in local computer ? what is the value of `document.domain` ? – Raptor Nov 26 '12 at 06:44
  • It will be `localhost` or the ip address of the machine (typically `127.0.0.1`), depending on what is in the url address bar. – Ash Clarke May 07 '13 at 09:41
1

While some of these solutions may work, none of them follow best practices. Many assign global variables and you may find yourself making calls to multiple parent variables or functions, leading to a cluttered, vulnerable namespace.

To avoid this, use a module pattern. In the parent window:

var myThing = {
    var i = 0;
    myFunction : function () {
        // do something
    }
};

var newThing = Object.create(myThing);

Then, in the iframe:

function myIframeFunction () {
    parent.myThing.myFunction();
    alert(parent.myThing.i);
};

This is similar to patterns described in the Inheritance chapter of Crockford's seminal text, "Javascript: The Good Parts." You can also learn more at w3's page for Javascript's best practices. https://www.w3.org/wiki/JavaScript_best_practices#Avoid_globals

wjl2
  • 11
  • 3
0

With Firefox and Chrome you can use :

<a href="whatever" target="_parent" onclick="myfunction()">

If myfunction is present both in iframe and in parent, the parent one will be called.

snowflake
  • 1,750
  • 2
  • 17
  • 40
  • it doesn't work. Here is my demo: http://dotku.github.io/tech/html/iframe/iframe_function_container.html – Weijing Jay Lin Mar 21 '16 at 18:50
  • As stated by Ash Clarke, the javascript you want to call from the child iframe needs to be in the head of the parent. – snowflake Mar 22 '16 at 05:44
  • The accepted answer does not need the script to be in the head. I didn't test if this solution also no longer needs for the script to be in the head or not. – Guy Schalnat Sep 07 '16 at 16:53
0

A plugin helper gist that allows the parent window to call the child iframe windows functions and vice-versa, but all calls are asynchronous.

https://gist.github.com/clinuxrulz/77f341832c6025bf10f0b183ee85e072

This will also work cross-origin, but can only call functions that you export to the iframe from the parent and the parent window can only call funtions the iframe exports.

clinux
  • 2,984
  • 2
  • 23
  • 26