2

I've been having a problem with some of my code. I won't post the whole code, since the page is quite complex, but here's a simplified version.

Essentially I have a visualforce page "TestPage"

<apex:page id="TestPage" controller="ControllerTestPage">
<apex:form>
    <apex:repeat value="{!allForms}" var="form">
        <c:CustomForm FormToRender="{!form}"/>
    </apex:repeat>
</apex:form>
</apex:page>

I have a custom component "CustomForm" that renders a form on the page.

The important parts of this component is below:

<apex:actionRegion >
    <apex:actionFunction name="{!formPrefix}submitForm" action="{!submitForm}"/>

    <!--Generates a form for the user to fill in !-->
    <apex:outputPanel id="formBuilder">
    <button type="button" class="btn-primary onclick="{!formPrefix}readyFormSubmit();">Submit</button>
    <script>
    function {!formPrefix}readyFormSubmit()
    {
        //if no uploads to handle on form, submit form
        if({!formPrefix}dataIdToDownloadMap == undefined || {!formPrefix}dataIdToDownloadMap.size == 0)
            {!formPrefix}submitForm();
        //otherwise handle uploads before submitting form
        else
        {
            ...
        }

    }
  </script>
  ...

The issue is that I need to call the "readyFormSubmit" javascript before using the action function to submit the form to make sure uploads are handled correctly. Now the Salesforce documentation states "Note: Beginning with API version 23 you can't place apex:actionFunction inside an iteration component — apex:pageBlockTable, apex:repeat, and so on. Put the apex:actionFunction after the iteration component, and inside the iteration put a normal JavaScript function that calls it." (https://developer.salesforce.com/docs/atlas.en-us.pages.meta/pages/pages_compref_actionFunction.htm)

But this solution isn't possible for me since the action function is part of the custom component. Visualforce refuses to call the action function if it's in the repeater. If I remove the repeater, like this:

<apex:page id="TestPage" controller="ControllerTestPage">
<apex:form>
        <c:CustomForm FormToRender="{!allForms[0]}"/>
</apex:form>
</apex:page>

then the custom form works perfectly. Are there any workarounds for this sort of problem?

0

You just need to pass the form in as a parameter, and adjust throughout your code.

<button type="button" class="btn-primary onclick="readyFormSubmit('{!formPrefix}');">Submit</button>

...

<!-- in page, not individual component -->
<apex:actionFunction name="submitForm" action="{!submitForm}">
  <apex:param name="formPrefix" assignTo="{!submittedFormPrefix}" value="" />
</apex:actionFunction>

...

// Also at the page level, not individual component
function readyFormSubmit(formPrefix)
{
    //if no uploads to handle on form, submit form
    if(dataIdToDownloadMap[formPrefix] == undefined || dataIdToDownloadMap[formPrefix].size == 0)
        submitForm(formPrefix);
    //otherwise handle uploads before submitting form
    else
    {
        ...
    }
}

You'll probably need to adjust this code to meet your needs, as this answer only addresses code actually included in the question, but hopefully you see the pattern and can extrapolate from there.

4
  • Unfortunately, this approach won't work. "SubmitForm" is an action on the controller of the custom component. This is a component used in multiple visualforce pages, so it won't really be practical to create a submitForm function on each page that uses it. If there is a solution where I can eliminate the actionFunction all together, that's really what I'm looking for. Jul 19 '21 at 17:21
  • @HansDonkersloot No, that won't work out in your favor. The method would need to be in the page's controller. Remember that JavaScript is shared across the entire page in Visualforce. This design would work very well in Aura/LWC, but not in Visualforce. You'll have to change the button to an apex:commandButton instead, and do any validation you want to do by using onclick="{!formPrefix}validate()" or something like that.
    – sfdcfox
    Jul 19 '21 at 19:23
  • perhaps I'm misunderstanding, but I'm not sure why the method needs to be in the page's controller. The {!formPrefix} is used to make each customForm javascripts calls unique. Each form has a unique Id set to it when it's created. this makes the JavaScript definitions unique to the form. For example, {!formPrefix}readyFormSubmit() is turned into: form_0_readyFormSubmit() while the next form would have the definition: form_1_readyFormSubmit() -- Again, perhaps I'm not understanding something, but I've used this approach in the past to define JS functions in a repeater Jul 19 '21 at 21:11
  • @HansDonkersloot As the docs say, it's no longer allowed. Presumably there was a bug or something, so they "outlawed" it. Repeating logic in Visualforce is rather buggy as a whole, based on the tech it's based on (JSP). You'd be better off writing code in Lightning and using Lightning Out.
    – sfdcfox
    Jul 19 '21 at 21:52

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.