window.opener.$A syntax gives – permission denied to access property “$A” error

Problem statement:

When we try to access the ‘window.opener.$A’ property of lightning component present in the parent from a javascript snippet present in a child window (Visual force page) we get the error ‘Permission denied to access property “$A”‘

Task:

We intend to open a child window on click of a button present in a lightning component. The child window would present the user with certain selectable data. Once the user selects certain row, and clicks submit, the row data(obtained by the child window using callouts) has to be returned to the parent lightning component/App which opened the child window(containing VF page).

Activities completed:

  • We created a ‘Application’ level global access event named as ‘ICDCodeSelected’ (Syntax for which is as follows), which we want to utilize to pass data from child window to parent window’s lightning component.

    <aura:event type="APPLICATION" description="Event template" access="global">
        <aura:attribute name='CODE' type='String'/>
        <aura:attribute name='DESCRIPTION' type='String'/>
    </aura:event>
    
  • As per mentioned in SF documentation : Firing Lightning Events from Non-Lightning Code, we have added following code snippet to our Visualforce Page javascript which is as follows:

    var myExternalEvent;
    if(window.opener.$A && (myExternalEvent = window.opener.$A.get("e.c:ICDCodeSelected"))) {
        myExternalEvent.setParams({CODE:'M84.3',DESCRIPTION:'Home visit for the evaluation and management of a new pat..'});
        myExternalEvent.fire();
    }
    

Note:

Please note that the error appears for ‘window.opener.$A’ only, when we include the lightning dependency application/component inside the VF page (child window) using lightning out, we can access the $A component ad hence can get the Event to fire it, but it fires only in the context of the child window, and their is not update on the parent lightning page.

Your inputs/comments/suggestions on the above issue resolutions would be pretty helpful for us.

Thanks,
Abhijeet Bhandari

Answer

A solution for similar problem has been provided here https://developer.salesforce.com/blogs/developer-relations/2017/01/lightning-visualforce-communication.html

Some relevant section from the above blog:

Visualforce Page to Lightning Component

In this second scenario, we still have the same arrangement: a Visualforce page wrapped in a Lightning component. This time we need communication to happen in the opposite direction: The Visualforce page sends messages to the Lightning component.

Sending the Message in a Visualforce Page

This time, we invoke postMessage() on parent. This is a reference to the parent window, in other words the main window in Lightning Experience that hosts Lightning components.

<apex:page>
  <input id="message" type="text"/>
  <button onclick="sendToLC()">Send to LC</button>

  <script>
    var lexOrigin = "https://yourdomain-dev-ed.lightning.force.com";

    function sendToLC() {
       var message = document.getElementById("message").value;
       parent.postMessage(message, lexOrigin);
    }

  </script>
</apex:page>

Code highlights:
lexOrigin is the origin (protocol + port + host) Lightning Components are
loaded from
The message field is used to capture the simple string message we will
send to the Lightning Component

The second argument of postMessage() is the origin of the parent
window.
Again, the event will not be sent if the content of the parent window at the
time postMessage() is called wasn’t loaded from lexOrigin.

Receiving the Message in a Lightning Component

To receive the messages in your Lightning Component, you set up a listener for
message events:

Component:

<aura:component implements="flexipage:availableForAllPageTypes" 
            access="global">

<aura:attribute name="vfHost" type="String" 
    default="yourdomain-dev-ed--c.na35.visual.force.com"/>

<aura:handler name="init" value="{!this}" action="{!c.doInit}"/>

<iframe aura:id="vfFrame" src="{!'https://' + v.vfHost + '/apex/myvfpage'}"  
/>     
  </aura:component>

Controller:

({
    doInit : function(component) {
     var vfOrigin = "https://" + component.get("v.vfHost");
     window.addEventListener("message", function(event) {
        if (event.origin !== vfOrigin) {
            // Not the expected origin: Reject the message!
            return;
        }
        // Handle the message
        console.log(event.data);
    }, false);
  }
 })

Code Highlights:
vfOrigin is the origin (protocol + port + host) Visualforce pages are loaded
from. This is where we expect the messages to come from.

event.origin is the actual origin of the window that sent the message at the
time postMessage() was called. You should always verify that the actual origin
and the expected origin match and reject the message if they don’t.

event.data is the message sent from the other window With this
infrastructure in place, the Lightning component can now listen for events sent
by the Visualforce page and forward any relevant events to other Lightning
components on the page using standard Lightning application events.

Attribution
Source : Link , Question Author : Abhijeet Bhandari , Answer Author : sIQh

Leave a Comment