[SalesForce] Use visualforce page from Buttons, Links, and Actions in custom lightning component in case of S3 Amazon Uploader

Is it possible to use a Visualforce Page from Buttons, Links, and Actions in custom lightning component in case of S3 Amazon Uploader?

I have an object NEILON__File__c. The object in its Buttons, Links, and Actions has the following pages:

enter image description here

enter image description here

<!--**********************************************************************************
* Copyright © 2015, Neilon Inc.
* All rights reserved
*
* VisualForce Page: edEditFile
* Created by Anil Meghnathi

* - Edit file in multi upload file component

* - Modifications:
* - Anil Meghnathi - Initial 
***********************************************************************************-->
<apex:page extensions="NEILON.edEditFileController" title="{!$Label.neilon__new} {!$ObjectType.NEILON__File__c.label}" sidebar="false" showHeader="true" tabStyle="Amazon_File_System__tab" standardController="NEILON__File__c">
    <c:apJsAndCssIncludeComponent importJquery="true"
                              importAppurinUtil="true"
                              importJQueryLayout="false"
                              importFancyTree="false"
                              importJqGrid="false"
                              importEasyTooltip="true"
                              importAppurinCss="true"
                              importCkEditor="false"
                              importGnattChart="false"
                              importLightningDesign="true"/>

    <apex:outputPanel rendered="{!isError}">
        <apex:pagemessages id="pageLoadErrorMessage"/>
        <script>
            Appurin.lightning.createLightningPageMessage({'classicPageMessageId' : '{!$Component.pageLoadErrorMessage}'});   
        </script>
    </apex:outputPanel>

    <apex:panelGroup rendered="{!!isError}">
        <head>
            <script>
                var uploadFileWindowURL = '{!JSENCODE(uploadFileURL)}';
                if(Appurin.lightning.isLightningExperience()){
                    Appurin.lightning.navigateToURL(uploadFileWindowURL, false);
                } else{
                    window.open(uploadFileWindowURL,"_self");
                }
            </script>
        </head>
    </apex:panelGroup>
</apex:page>

This page is used as a button on a record details page. When a user clicks it with the record (of any type) being opened it allows to upload a related to the record file to Amazon.

Now I want to be able to upload files in the same way from my custom lightning component. The easiest way to do it as I can see now is to incorporate this button (visualforce page actually) into my lightning component and style it to my needs.

How should I pass the Id of the record for which I want to upload a related file?

Best Answer

The way you can achieve it would be hosting your vfpage in a lightning component using an Iframe and use postMessage() function to send parameters from lightning component to vfpage.

Your lightning component that hosts the vfpage:

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

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

    <!-- Input field for message "data" -->
    <lightning:input type="text" label="Message:" value="{!v.message}"/>
    <lightning:button label="Send to VF" onclick="{!c.sendToVF}"/>

    <!-- The Visualforce page to send data to -->
    <iframe aura:id="vfFrame" src="{!'https://' + v.vfHost + '/apex/myvfpage'}"/>

</aura:component>

controllerjs

({
    sendToVF : function(component, event, helper) {
        var message = component.get("v.message");
        var vfOrigin = "https://" + component.get("v.vfHost");
        var vfWindow = component.find("vfFrame").getElement().contentWindow;
        vfWindow.postMessage(message, vfOrigin);
    }
})

To receive the messages in your Visualforce page, you simply set up a listener for message events:

<apex:page>

<script>
    var lexOrigin = "https://yourdomain-dev-ed.lightning.force.com";
    window.addEventListener("message", function(event) {
        if (event.origin !== lexOrigin) {
            // Not the expected origin: reject message!
            return;
        }
        // Handle message
        console.log(event.data);
    }, false);
</script>

</apex:page>

There are two important things you need to know about Visualforce pages running in Lightning Experience:

Different DOMs. A Visualforce page hosted in Lightning Experience is loaded in an iframe. In other words, it’s loaded in its own window object which is different from the main window object where the Lightning Components are loaded.

Different Origins. Visualforce pages and Lightning Components are served from different domains. For example, if you are using a developer edition:

  1. Lightning Components are loaded from a domain that looks like this: yourdomain-dev-ed.lightning.force.com
  2. Visualforce pages are loaded from a domain that looks like this: yourdomain-dev-ed–c.na35.visual.force.com

The browser’s same-origin policy prevents a page from accessing content or code in another page loaded from a different origin (protocol + port + host). In our case, that means that a Visualforce page can’t use the parent window reference to access content or execute code in the Lightning Component wrapper. Similarly, the Lightning component can’t use the iframe’s contentWindow reference to access content or execute code in the Visualforce page it wraps. These restrictions are enforced for very good reasons. But fortunately, there is also an API (otherWindow.postMessage()) that provides a secure approach (when used properly) to exchange messages between different window objects with content loaded from different origins.

window.postMessage() is a standard

Communicating between Lightning Components and Visualforce Pages