9

I am trying to complete a VF page section that my sales-staff will be utilizing to add information to custom fields when a condition is met inside of the Account object. I have the custom page built and deposited into the account layout; but my final hurdle is what happens when the VF section is saved. When the 'Save' command button is clicked, the entire page is deposited into the VF section. The VF page when accessed directly works perfectly; it's only when the section is used inside of the larger page layout is the 'window inside window' effect seen. An F5 rectifies this; and returns the section back to normal but I cannot for the life of me figure out how to avoid this extra step. I modeled the code after this example found on developerforce:

http://developer.force.com/cookbook/recipe/dynamically-updating-a-page

Any help would be appreciated.

9

From the recipe change the save button from

<apex:commandButton value="Save" action="{!save}"/>

to

<apex:commandLink value="Save" action="{!save}" 
    target="_parent" styleClass="btn" 
    style="text-decoration:none;padding:4px;">

Since commandlink offers a target attribute I make use of it and make the command link exactly like the button using styleclass and style attributes

I tried even the command button with onclick approach but the child page constantly reloaded with the side bar and headers and did not look like it was inline. The commandlink is something I have worked hence the solution above, but it could be done using commandbutton if tweaked a bit more. Since we have what is required I did not push futher:)

0
8

An additional mechanism to consider in the event that you can't or don't want to use an <apex:commandLink with the target attribute set to _parent is to use a javascript statement to cause the parent page to refresh itself after successful saving.

The idea here is that you only render the script panel that executes the page refresh at the time you want the outer page to automatically reload (i.e. pressing F5). In this example the script block is displayed after the user clicks save (successfully) and the page inside the iframe (the VF embedded in the page layout) is being rendered back to the browser. The browser executes the now-visible javascript and the outer page is reloaded.

You might also consider setting the showHeader="false" sidebar="false" attributes on the page tag to disable those features if this page is going to be used exclusively embedded in another page layout.

VF Page embedded in a page layout (iframe):

<apex:page standardController="Account" extensions="yourExtensionClass" showHeader="false" sidebar="false">
    <apex:form>

    <apex:pageMessages />

    <apex:outputPanel id="refreshPanel" rendered="{!refreshPage}">
        <!-- This panel is only shown when the controller wants the parent page to perform a 'reload' -->
        <script>
            // force the browser to reload the 'top' page using the current URL
            window.top.location.href = window.top.location.href;
        </script>
    </apex:outputPanel>

    <!-- Your existing stuff -->

    </apex:form>
</apex:page>

The controller extension class:

public with sharing class yourExtensionClass {

    public Boolean refreshPage { get; set; }
    public ApexPages.StandardController stdController { get; set; }

    public yourExtensionClass(ApexPages.StandardController ctrl) {
        stdController = ctrl;

        // initialize the refresh value as false
        refreshPage = false;
    }

    public PageReference save() {

        // use the standard controller's save method
        PageReference pRef = stdController.save();

        if (pRef != null) {
            // set this value last, after successful saving to cause the VF page to show the javascript block
            refreshPage = true;
        }

        return pRef;
    }
}
4
  • Nice solution, but for me my browser gives me error "Uncaught DOMException: Blocked a frame with origin "https://<mydomain>--c.cs10.visual.force.com" from accessing a cross-origin frame." So sad. I even tried adding the salesforce and force.com URLs to Setup | Security Controls | CORS to no avail.
    – Doug Ayers
    Nov 2 '16 at 20:19
  • The platform has changed a tad since I penned this answer two years ago. Haven't had to test this mechanism in a while to see if it still operates as described. Are you testing and seeing that error in classic or lightning or both?
    – Mark Pond
    Nov 2 '16 at 20:53
  • Classic. My guess it's due to some new iframe security / cross-domain policies either per Salesforce or per Chrome browser. Thanks
    – Doug Ayers
    Nov 2 '16 at 21:24
  • I've posted my twist to @Rao's answer below, salesforce.stackexchange.com/a/147007/987 Thanks!
    – Doug Ayers
    Nov 2 '16 at 21:39
3

@Rao's answer works for me in Classic as of Winter '17 release. But if you have a form the user is submitting and you get back errors you may not want the page to have opened in the parent frame, perhaps you want the form to stay where it is and only pop open into the parent frame on success.

This is how I approached it:

  1. Apex controller has a boolean field that the save method sets to true (if success) or false (if errors)
  2. The visualforce page uses the apex:commandButton's oncomplete to call a javascript function
  3. The javascript function checks the boolean field and if true then opens link in parent window

Visualforce Page

    <apex:page standardController="Case" extensions="YourCustomController">

        <script src="https://code.jquery.com/jquery-2.2.4.min.js" integrity="sha256-BbhdlvQf/xTY9gja0Dq3HiwQF8LaCRTXxZKRutelT44=" crossorigin="anonymous"></script>
        <script>$j = jQuery.noConflict();</script>

        <apex:form>

            <apex:pageMessages id="theMessages"/>

            <apex:pageBlock mode="maindetail">

                <apex:pageBlockButtons location="bottom">
                    <apex:commandButton value="Save" action="{!save}" rerender="theMessages,reloadPagePanel" oncomplete="reloadPage();"/>
                </apex:pageBlockButtons>

                <!-- your page content -->

            </apex:pageBlock>

            <apex:outputPanel id="reloadPagePanel" style="display:none">

                <apex:outputLink id="caseDetailLink" value="/{!Case.Id}" target="_parent"/>

                <script>
                    function reloadPage() {
                        if ( '{!success}' == 'true' ) {
                            $j('[id$=caseDetailLink]')[0].click();
                        }
                    }
                </script>

            </apex:outputPanel>

        </apex:form>

    </apex:page>

Apex Controller

    public with sharing class YourCustomController {

        public Boolean success { get; set; }

        public YourCustomController( ApexPages.StandardController stdController ) {
            this.success = false;
        }

        public void save() {

            SavePoint sp = Database.setSavePoint();

            try {

                // do stuff

                ApexPages.addMessage( new ApexPages.Message( ApexPages.Severity.CONFIRM, 'Time Logged' ) );

                this.success = true;

            } catch ( Exception e ) {

                Database.rollback( sp );

                System.debug( LoggingLevel.ERROR, e.getMessage() + ' : ' + e.getStackTraceString() );

                ApexPages.addMessage( new ApexPages.Message( ApexPages.Severity.ERROR, e.getMessage() ) );

                this.success = false;

            }

        }

    }
-3

Please try this below link, it will work for sure:) 

<apex:commandLink  value=" Click Here" onclick="window.top.location='/{!accountid}'; return false"/> 

Pass the record id  and you are all set.

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service, privacy policy and cookie policy

Not the answer you're looking for? Browse other questions tagged or ask your own question.