2

I've come across a situation where the mere presence of an invokeAction call inside my JavaScript code causes VF to display a 'no remoted actions found to resolve' page.

In short, I have a button that reveals an outputPanel, and this contains a second button that invokes a remote method via JS (which is also contained therein). The problem is, I only need to click the 'reveal' button and the error page is shown. I suspect this is due in part to VF over-zealously parsing my code, because it happens even if the invokeAction code is present but commented out.

However, if I relocate the whole <script> section outside my <form> then everything works perfectly, and I'm wondering why this might be. FWIW, it makes no difference whether I declare the controller & remote method as global or public.

On a related note, one way of getting around this is to simply invoke the remote method directly:

MyController.doRemoteThing(arg1, arg2, f(r,e){});

Is there any reason not to do it this way in general?

PAGE

<apex:page controller="MyController">
    <apex:form>
        <apex:commandButton action="{!ButtonPressed}" value="{!IF(wasPressed, 'Hide', 'Reveal')}" reRender="idPanel,idCmd" id="idCmd" />
        <apex:outputpanel id="idPanel">
            <apex:outputPanel rendered="{!wasPressed}">

                <!-- move this outside the <form> and everybody is happy! -->
                <script>
                    function makeRemoteCall() {
                        Visualforce.remoting.Manager.invokeAction(
                            '{!$RemoteAction.MyController.doRemoteThing}', 'abcd', 'efgh', 
                             function (result, event) { alert(result); });
                    }
                </script>

                <button onclick="makeRemoteCall();return false;">Do Remote Thing</button>
            </apex:outputPanel>
        </apex:outputPanel>
    </apex:form>
</apex:page>

CONTROLLER

public class MyController {
    public MyController() { wasPressed = false; }
    public Boolean wasPressed {get; set;}
    public void ButtonPressed() { wasPressed = !wasPressed; }

    @RemoteAction public static String doRemoteThing(String str1, String str2) {
            return str1 + str2;
        }
}
1

You shouldn't try to load scripts dynamically after the page load without a very good reason, and this is true of any website you develop, not just Visualforce. Even so, you doubly shouldn't try to use expressions of any sort in a script that is rendered dynamically, because it can cause all sorts of unusual errors to crop up (and not just with remoting).

In fact, I would go so far as to say you should avoid trying to mix JavaScript and Visualforce at all for the best experience. While it's true that expressions are allowed within script blocks, they are generally fraught with pitfalls that would be avoided if one simply remoted exclusively; you no longer have to worry about proper escaping, order of re-render execution, or any other nonsense.

Interestingly, if you set the flag to true in the constructor, then click the "hide" button, and check your console, the function makeRemoteCall() still exists. This means that there is at minimum a glitch with re-rendering scripts anyways. There may be some type of protection mechanism that the Visualforce library uses to avoid overwriting existing functions, or perhaps the function is rendered out of existence in the view state once it is hidden, thus causing the crash you've observed.

Either way, load your scripts when the DOM first loads. Do not try to be a hero by loading scripts at the last possible instant, because it is slower than just loading the resource immediately (you're not preventing the load time, only offsetting to a more noticeable point in the user experience). If you really want the function to be loaded "lazily", include it as a static resource using HTML5's "async" attribute; it will still be available by the time you need it. However, using that logic, you'll lose the ability to use expressions to bind to the function correctly.

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.