Skip to content

Instantly share code, notes, and snippets.

@sekia
Created March 19, 2020 08:09
Show Gist options
  • Save sekia/8ec981301a1f8ecef90e3fcc8719641f to your computer and use it in GitHub Desktop.
Save sekia/8ec981301a1f8ecef90e3fcc8719641f to your computer and use it in GitHub Desktop.
Example of communication with same-origin iframe using |window.postMessage|.
<!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>
<!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