function readOnly(count){ }
Starting November 20, the site will be set to read-only. On December 4, 2023,
forum discussions will move to the Trailblazer Community.
+ Start a Discussion
frelepfrelep 

Using Javascript (JQuery) in an Apex iframe

Hi,

 

In a visualforce I used an autocomplete feature (in JQeury) for an input field and that works great.

It's based on a remote action define in my controller which is called by the javascript.

 

Now, I want to put my visualforce in an apex iframe but when the frame is shown, the warning message : "Javascript proxies were not generated for controller myController : may not use public remoted methods inside an iframe".

And my apex remote action is of course never called.....

 

Do someone has an idea to resolve that ?

 

Thanks in advance for your help.

 

 

Best Answer chosen by Admin (Salesforce Developers) 
frelepfrelep

Hi,

 

I feel a little bit alone ;-)

 

So for those who experience this problem, simply declare as global:
- The controller of the Visualforce
- The method declared in remote action

 

If it can help someone, you're welcome ;-)

 

Enjoy !

All Answers

TheSwamiTheSwami

Can you post the code here?  (as simply as possible)

frelepfrelep

Hi,

 

Thanks for your interest to help me.

 

So I tried to reduce the source code length as I can (see after) but with the elements below, you can put on a platform to test (just need jQuery as resource and JSONObject class).

 

Explanations for the operation :
- Visualforce page "Main" which is called manually (/apex/Main) and integrate inside an iframe
- Visualforce page "searchOpportunity" which is included in the iframe
- Apex controller "SearchOpportunityController" which is the controller of the page "searchOpportunity"

 

For the principle of autocomplete:
The user enters the characters (at least 3) the name of this opportunity and launcheda remoteaction in the controller which will then get a list of opportunities and thecorresponding display as a list in which the user can select the desired opportunity.

First I called the page "Main" (apex/Main), a warning (error) popup is displayed and apex remote action is never called :-(

 

 

Then I called the page "SearchOpportunity" (apex/SearchOpportunity), all works well :-) it's not enough....

 

 

But I need absolutely of course a Main page to integrate the page (as an iframe) in another GUI to integrate a sidebar, change the iframe source, etc...

 

Can you help me to resolve this restriction ?

Thanks in advance.

 

Visualforce "Main" 

<apex:page controller="MainController" showHeader="false" sidebar="false">
    <div>
        <iframe height="600px" id="theIframe" name="theIframe" src="/apex/searchOpportunity" width="100%" frameborder="0"></iframe>
    </div>
</apex:page>

 Visualforce "searchOpportunity"

<apex:page controller="SearchOpportunityController" showHeader="false" sidebar="false">

<script src="{!URLFOR($Resource.jQueryFiles, 'js/jquery-1.6.2.min.js')}"></script>
<script src="{!URLFOR($Resource.jQueryFiles, 'js/jquery-ui-1.8.16.custom.min.js')}"></script>
<apex:stylesheet value="{!URLFOR($Resource.jQueryFiles, 'css/smoothness/jquery-ui-1.8.16.custom.css')}"/>
 
<apex:form id="formSearchOrCreateOpportunity">

    <apex:pageBlock id="pageblock" title="{!$ObjectType.Opportunity.label}">  

        <apex:pageMessages />

        <apex:outputPanel id="oppNameArea"  >
            <apex:pageBlockSection columns="1" collapsible="false"  >
                
                
                <apex:pageBlockSectionItem >
                    
                    <!-- Opportunity field name label --> 
                    <apex:outputLabel value="{!$ObjectType.Opportunity.fields.Name.label}" />
                    
                    <!-- Opportunity field name value and a label to indicate if new or existing opportunity -->
                    <apex:outputPanel styleClass="requiredInput" layout="block" id="pwPanel" >
                        <apex:outputPanel styleClass="requiredBlock" layout="block"/>
                        <apex:inputText id="opp_account_name" label="Opportunity name" value="{!searchedCharacters}" styleClass="inputtext autocompleteOpportunity" required="true" style="width:50%;display:block;float:left" onchange="ResetOpportunity();"/>      
                    </apex:outputPanel>
                    
                </apex:pageBlockSectionItem>
                
                <!-- Function launched when the user enter characters to load matching opportunities -->
                <apex:actionFunction name="loadOpportunity" action="{!loadOpportunity}" immediate="true">
                    <apex:param name="p" assignTo="{!oppIdSelected}" value="" />
                </apex:actionFunction> 
                 
                <script>
                    $(function() {
                        var cache = {},
                            lastXhr;
                        $( ".autocompleteOpportunity" ).autocomplete({
                            //The loading of the list of opportunities is launched with at least 3 characters
                            minLength: 3,
                            //Loading the list of opportunities
                            source: function( request, response ) {
                                var term = request.term;
                                if ( term in cache ) {
                                    response( cache[ term ] );
                                    return;
                                }
                                lastXhr = SearchOpportunityController.getListOpportunity(request, function( data, status, xhr ) {
                                    cache[ term ] = data;
                                    if ( xhr === lastXhr ) {
                                        response( data );
                                    }
                                }, {escape:true});
                            },
                            //Loading the opportunity from the item selected in the list
                            select: function( event, ui ) {
                                loadOpportunity(ui.item.id);
                            }
                        });
                    });
                </script>
                
                <!-- Input text (hidden) to store the Opportunity id selected in the list -->
                <apex:inputText id="id_opp" value="{!oppIdSelected}" rendered="false"  />
                
            </apex:pageBlockSection>                    
        </apex:outputpanel>
        
    </apex:pageBlock>
</apex:form>

</apex:page>

 Apex controller "SearchOpportunityController"

public with sharing class SearchOpportunityController {
      
    /**
    * Inner class to create an JQueryUIAutoComplete wrapper.
    */
    public class JQueryUIAutoCompleteWrapper {
    
        public String label {get; set;}
        public String id {get; set;}

        public JQueryUIAutoCompleteWrapper() {
            label = null;
            id = null;
        }
    }  
      
    //Attributes used for the opportunity name autocomplete
    public String searchedCharacters{get;set;}
    public String oppIdSelected{get;set;}  
      
    //Attributes for the objects manipulated with the opportunity  
    public Opportunity myOpportunity{get;set;}      
          
    /**
    * Constructor.
    */
    public SearchOpportunityController() {
        myOpportunity = new Opportunity();
    } 
    
    /**
    * Load the opportunity from the opportunity id selected.
    */
    public void loadOpportunity() {
        Opportunity[] myOpportunities = [Select id, name from Opportunity where id =: oppIdSelected limit 1];
        myOpportunity = myOpportunities[0];
    } 
    
    /**
    * Action launch to return the list of opportunities matched from the input.
    */ 
    @RemoteAction
    public static List<JQueryUIAutoCompleteWrapper> getListOpportunity(String JSONString) {
    
        JQueryUIAutoCompleteWrapper[] listOpportunity = new List<JQueryUIAutoCompleteWrapper>();
        
        //Build JSON object from input
        JSONObject JSON = new JSONObject( JSONString );

        //Build searched pattern
        String searchedPattern = String.valueof(JSON.get('term')).trim() + '%';
        
        //Get list of matching opportunities id's and labels
        for(Opportunity oppName:[select id, Name from Opportunity where Name like :searchedPattern order by Name, id limit 10000]) {
            JQueryUIAutoCompleteWrapper oppW = new JQueryUIAutoCompleteWrapper();
            oppW.label = oppName.Name;
            oppW.id = oppName.id;
            listOpportunity.add(oppW);            
        }
        return listOpportunity;
    }
}

 

 

 

 

frelepfrelep

Hi,

 

Finally after many tests, I think I found the solution.

 

The warning (error) popup message has clearly oriented myself to the use of the "global" keyword and I found some complements on the 2 following pages:

http://www.salesforce.com/us/developer/docs/pages/Content/pages_js_remoting.htm

http://www.salesforce.com/us/developer/docs/pages/Content/pages_js_remoting_example.htm

 

I'll let you know whether it works really well....


frelepfrelep

Hi,

 

I feel a little bit alone ;-)

 

So for those who experience this problem, simply declare as global:
- The controller of the Visualforce
- The method declared in remote action

 

If it can help someone, you're welcome ;-)

 

Enjoy !

This was selected as the best answer
seattle_developerseattle_developer

You rock @frelep!!

 

Thanks!

JamesAtCloudbuildersJamesAtCloudbuilders

I have a solution for this - it turns out Remoting doesn't work within iframes. Since "Development Mode" uses iframes, you can't use a public remote method if development mode is turned on for your user.

 

Turning off dev mode works around the issue, although I think this is clearly a salesforce bug that needs fixing. 

rvaderrvader

thank you JamesAtCloudbuilders!!!

"clearly a salesforce bug that needs fixing" ... I completely agree.

frelepfrelep

Oh yeah, a bug to fix because current users like Sales for example should not have the "Developer mode" ;-)

 

mrjones101mrjones101

Thanks!  Needed this big time.

GVelGVel

Spot on.

Thanks

admintrmpadmintrmp

I agree that this should be fixed. If I'm completely honest, I don't wish to turn my @RemoteAction method to global, especially since we cannot remove it afterwards.

 

I completely understand that the annotated method should only be used outside an iFrame, but this is within Salesforce's own iFrame. C'mon! :-)