1

I have a VF page where I upload a .csv file and display the columns on the page in a table. It all works fine if I don't try and add a spinner, which requires me to rerender the page.

If I don't use the actionRegion, I get the error

apex inputFile can not be used in conjunction with an action component

If I rerender the entire page, it loses the blob value of the input file, as the controller code

csvAsString = csvFileBody.toString();

throws the error:

System.NullPointerException: Argument cannot be null

If I rerender only the table, nothing is displayed in the table. I'm tearing my hair out trying to get it to work with the spinner and displaying the results!

<apex:page controller="ImportTestDataFromCSVController">
<script>
function handleFile(file) {
    var fullPath = document.getElementById(file.id).value;
    var split = fullPath.split(/(\\|\/)/g).pop();
    document.getElementById("fileName").innerHTML = split;
}
</script>
<apex:slds />
<apex:form id="importform">
    <apex:actionstatus id="spinnerStatus">
        <apex:facet name="start">
            <div class="slds-spinner_container" style="position:fixed !important;">
                <div class="slds-spinner--brand slds-spinner slds-spinner--large" role="status">
                    <span class="slds-assistive-text">Loading</span>
                    <div class="slds-spinner__dot-a"></div>
                    <div class="slds-spinner__dot-b"></div>
                </div>
            </div>
        </apex:facet>
    </apex:actionstatus>
    <apex:pagemessages id="pgmsg"/>
    <apex:pageBlock >
        <article class="slds-card">
            <div class="slds-card__header slds-grid">
                <header class="slds-media slds-media_center slds-has-flexi-truncate">
                    <div class="slds-media__body">
                        <h2 class="slds-card__header-title">
                            <a href="javascript:void(0);" class="slds-card__header-link slds-truncate" title="Import Data">
                                <span>Import Data</span>
                            </a>
                        </h2>
                    </div>
                </header>
            </div>
            <fieldset class="slds-card__body slds-card__body_inner">               
                <div class="slds-card slds-p-around_medium">                        
                    <div class="slds-form-element slds-form-element_compound">
                        <div class="slds-form-element__control ">
                            <div class="slds-form-element__row">
                                <div class="slds-size_1-of-3 ">
                                    <div class="slds-size_2-of-3 ">
                                        <label class="slds-form-element__label" for="selobject">Select an Object</label>
                                        <apex:selectList id="selobject" value="{!selobject}" size="1" label="Select an Object" title="Select an Object" styleClass="slds-select">
                                            <apex:selectOptions value="{!items}"/>   
                                        </apex:selectList>
                                    </div>
                                </div>
                                <div class="slds-size_1-of-3">
                                    <div class="slds-file-selector slds-file-selector_files">
                                        <div class="slds-file-selector__dropzone">
                                            <apex:inputFile styleClass="slds-file-selector__input slds-assistive-text" onchange="handleFile(this)" accept="csv" id="importfile" value="{!csvFileBody}" filename="{!csvAsString}"/>
                                            <apex:outputLabel styleClass="slds-file-selector__body" for="importfile">
                                                <span class="slds-file-selector__button slds-button slds-button_neutral">
                                                    <svg class="slds-button__icon slds-button__icon_left" aria-hidden="true">
                                                        <use xmlns:xlink="http://www.w3.org/1999/xlink" xlink:href="/assets/icons/utility-sprite/svg/symbols.svg#upload"></use>
                                                    </svg>
                                                    Select File
                                                </span>
                                                <span id="fileName" class="slds-file-selector__text slds-medium-show">or Drop Files</span>
                                            </apex:outputLabel>
                                        </div>
                                    </div>
                                </div>
                                <div class="slds-size_1-of-3">
                                    <apex:actionRegion id="actreg">
                                        <apex:commandButton styleClass="slds-button slds-button--neutral" value="Import" action="{!importCSVFile}" status="spinnerStatus" rerender="pgmsg"/>
                                        <apex:commandButton styleClass="slds-button slds-button--neutral" value="Save" action="{!saveFile}" rendered="{!canSave}" status="spinnerStatus"/>
                                        <apex:commandButton styleClass="slds-button slds-button--neutral" value="Save Contact/User" action="{!saveFileAndUser}" rendered="{!canSaveContact}" status="spinnerStatus"/>
                                        <apex:commandButton styleClass="slds-button slds-button--neutral" value="Clear" action="{!Init}" rendered="{!canSaveContact || canSave}" status="spinnerStatus"/>
                                    </apex:actionRegion>
                                </div>
                            </div>
                        </div>
                    </div>
                </div>
            </fieldset>
        </article>
    </apex:pageBlock>
    <apex:pageBlock id="showimport">
            <apex:pageBlockTable id="importvalues" value="{!displayList}" var="rec">                
                <apex:repeat value="{!colHeaders}" var="FieldLabel"> 
                    <apex:column value="{!rec[FieldLabel]}"/> 
                </apex:repeat> 
            </apex:pageBlockTable>        
        </apex:pageBlock>
</apex:form>

1 Answer 1

3

The CSV file would be wiped out on reRender anyways, so you need to store the data elsewhere between actions on the page.

To get the desired effect, render the spinner using client-side code, and leave the page as-is.

<apex:page ...>
  <div id="spinner" class="slds-spinner_container slds-hidden">
    <!-- rest of spinner here -->
  </div>
  <apex:form>
    <!-- your form logic here -->
    <apex:commandButton action="{!...}" onclick="document.getElementById('spinner').classList.remove('slds-hidden')" ... />
  </apex:form>
</apex:page>

We hide it by default, and show it as appropriate. When the page reloads, the spinner will again be hidden.

Remember that apex:inputFile will wipe out the contents of the blob when another action occurs, so save the blob or the parsed results in another variable, a record, Platform Cache, or somewhere else, depending on your needs.

You might also choose to just port most of the logic over to plain JavaScript, or even use an Aura Lightning component! There's no need to do all the processing in Apex; do some parsing in the client, then pass the data to a @RemoteAction method on the server for final validation, etc, or you might also just use apex:remoteObjects to manipulate data in JavaScript directly.

7
  • Thanks for that! My Javascript knowledge is limited, as is my Lightning component knowledge (although I have created one!). If you have any examples for me to look at that would be great, but if not, I'll have a go when I have time to redevelop this.
    – Irene
    Commented Dec 29, 2019 at 20:29
  • But how to you hide again the spinner? For example if there are an error that I want to display on the form
    – Raphael D
    Commented Sep 30, 2021 at 8:52
  • @RaphaelD In this example, we don't use a reRender, so when the page completes the action, it reloads, and the default styles are reloaded, too. If you do use reRender, you can hide it with: oncomplete="document.getElementById('spinner').classList.add('slds-hidden')".
    – sfdcfox
    Commented Sep 30, 2021 at 9:21
  • thanks, if for example I have required fields on the form it will not reloads the page
    – Raphael D
    Commented Sep 30, 2021 at 9:37
  • I cannot use oncomplete because I have inputFile in the form
    – Raphael D
    Commented Sep 30, 2021 at 9:43

You must log in to answer this question.

Not the answer you're looking for? Browse other questions tagged .