Window.postMessage: chiamare una funzione del parent da un iframe

In passato spesso mi era capitata l’esigenza di dover chiamare dalla pagina di un iframe una funzione javascript contenuta nel parent ed ho sempre risolto facendo una semplice chiamata parent.MyParentFunction(); anche se con qualche dubbio relativo alla sicurezza.

Qualche giorno fa ho avuto la seguente richiesta: avendo un sito web che permette di effettuare l’embed di alcuni video, mi hanno chiesto di chiamare una funzione javascript di chi embedda i miei video al termine del video stesso.

Riprovando a soddisfare la richiesta con il codice utilizzato in passato mi sono reso conto che i browser si sono aggiornati in merito e giustamente mi bloccava la chiamata dicendi che si tentava di eseguire una chiamata cross origin.

Facendo un po di ricerca e di test ho trovato la risposta a questa problematica Window.postMessage() che consente tranquillamente la comunicazione cross-origin.

Potete documentarvi ai seguenti link (se fate una ricerca per window.postMessage trovate un bel pò di materiale): https://developer.mozilla.org/en-US/docs/Web/API/Window/postMessage
https://html.spec.whatwg.org/multipage/comms.html#web-messaging

Qui trovate la compatibilità con i vari browser:

http://caniuse.com/#search=postMessage

Di seguito subito un esempio di codice per effettuare l’implementazione.

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.'
}, "*");