Created
March 19, 2020 08:09
-
-
Save sekia/8ec981301a1f8ecef90e3fcc8719641f to your computer and use it in GitHub Desktop.
Example of communication with same-origin iframe using |window.postMessage|.
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
<!DOCTYPE html> | |
<html> | |
<head> | |
<meta charset="UTF-8" /> | |
<title>IFrame Content</title> | |
</head> | |
<body> | |
<form id="ui-container"> | |
<input id="ui" /> | |
<button type="submit">Apply Changes</button> | |
</form> | |
<script> | |
const appState = { | |
value: null, | |
}; | |
// App-specific UI logic(s). | |
const ui = document.getElementById('ui'); | |
ui.onchange = e => appState.value = e.target.value; | |
window.onmessage = ({ data, origin }) => { | |
console.log('[in-iframe] Got: ', { data, origin }); | |
// In production code ignore messages having unexpected |origin|. | |
// if (origin !== 'https://example.com') { return; } | |
// Initialize in-iframe app state here. | |
if (data.type === 'content/INITIALIZE') { | |
const { data: { state } } = data; | |
ui.value = state.value; | |
} | |
}; | |
// Sends (possibly updated) data back to parent app. | |
document.getElementById('ui-container').onsubmit = e => { | |
e.preventDefault(); | |
const parentWindow = window.parent; | |
parentWindow.postMessage( | |
{ | |
type: 'content/APPLY_CHANGES', | |
data: appState, | |
}, | |
'*', | |
); | |
}; | |
</script> | |
</body> | |
</html> |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
<!DOCTYPE html> | |
<html> | |
<head> | |
<meta charset="UTF-8" /> | |
<title>Parent Page</title> | |
</head> | |
<body> | |
Notice: this example won't work when loaded via file URL. | |
Run the command below and go to http://localhost:9000: | |
<pre> | |
$ python -m http.server 9000 | |
# If you're still using python 2, | |
# replace |http.server| with |SimpleHTTPServer|. | |
</pre> | |
<div> | |
Parent App's state: | |
<pre id="state-dump"></pre> | |
</div> | |
<iframe id="iframe-content" src="./content.html"></iframe> | |
<script> | |
function dumpState(state) { | |
const dumpContainer = document.getElementById('state-dump'); | |
dumpContainer.innerText = JSON.stringify(state); | |
} | |
const appState = { | |
value: 'blah blah blah', | |
}; | |
dumpState(appState); | |
const iframeElement = document.getElementById('iframe-content'); | |
const contentWindow = iframeElement.contentWindow; | |
contentWindow.onload = () => { | |
// Sends initialization message to app running in the iframe. | |
contentWindow.postMessage( | |
{ | |
type: 'content/INITIALIZE', | |
data: { state: appState }, | |
}, | |
// In production code you SHOULD specify target origin. | |
// e.g., 'https://example.com' | |
'*', | |
); | |
}; | |
// Event listener to apply in-iframe app changes to parent app's state. | |
window.onmessage = ({ data, origin }) => { | |
// In production code ignore messages having unexpected |origin|. | |
// if (origin !== 'https://example.com') { return; } | |
if (data.type === 'content/APPLY_CHANGES') { | |
// Hint: If the parent app is redux-based, simply dispatch the message | |
// as an action: | |
// store.dispatch(data); | |
Object.assign(appState, data.data); | |
dumpState(appState); | |
} | |
} | |
</script> | |
</body> | |
</html> |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment