3

I'm working on a vf page/controller. All of the code at this point is about 800 lines so I wont post it all but I have posted the items that are relevant.

Basically, there are 4 forms on the VF page. One of the forms (below) has an inputfile field with a submit button to run the upload action. The goal is to attach the file to the current case.

Because of the way inputfile works, it requires a full page reload which can result in loss of work for other forms. Instead of calling the upload directly, I want to call it from javascript so that I can warn the user if they are going to lose work. I have set the warning method to the onclick event.

The console logs all the correct values depending on the various situations. The upload method from the controller is never invoked (system.debug doesn't show up in logs and stack trace shows no calls to the method).

I did verify that there is an upload method on the VF page after it renders so I have no idea why the JS won't call the function -Or- why everything fails before the apex function is invoked.

I did notice this in the dev console after clicking the button but before the page reloads: enter image description here

Any advise would be appreciated.

Upload Method:

public pageReference upload() {
    system.debug('called');
    try {
        system.debug('try');
        insert tempAttachment;
    } catch (DMLException ex) {
        system.debug('catch');
        apexpages.addMessages(ex);
    } finally {
        system.debug('finally');
        resetNewComment();
    }
}

VisualForce Form:

<apex:form id="newAttachmentForm">
            <apex:actionFunction action="{!upload}" name="upload" id="afUpload"/>
            <apex:messages />
            <apex:pageBlockSection title="New Attachments" collapsible="false">
                <apex:inputFile fileName="{!tempAttachment.Name}" value="{!tempAttachment.body}" />
                <apex:commandButton value="Attach to Case" onclick="warning()" />
            </apex:pageBlockSection>
        </apex:form>

JS Function:

<script>
    function warning() {
        var body = document.getElementById("{!$Component.pNewComment.pbComposeEmail.ComposeEmailForm.pbsComposeEmail.emailBody}");
        var subject = document.getElementById("{!$Component.pNewComment.pbComposeEmail.ComposeEmailForm.pbsComposeEmail.emailSubject}");
        var to = document.getElementById("{!$Component.pNewComment.pbComposeEmail.ComposeEmailForm.pbsComposeEmail.emailTo}");
        var cc = document.getElementById("{!$Component.pNewComment.pbComposeEmail.ComposeEmailForm.pbsComposeEmail.emailCC}");
        var bcc = document.getElementById("{!$Component.pNewComment.pbComposeEmail.ComposeEmailForm.pbsComposeEmail.emailBCC}");

        //If the components have text, warn the user that their data will be lost
        if (body.value != '' || subject.value !='' || to.value != '' || cc.value != '' || bcc.value != '') {
console.log('content found');
            if (confirm('If you upload an attachment, the email message will be cleared. Proceed?')) {
console.log('upload accepted');
                upload();
                return true;
            } else {
console.log('upload rejected');
                return false;
            }
        } else {
console.log('no content located');
            upload();
            return true;
        }
    }
</script>
  • Don't use an input file - it's nearly as easy to use an input of type file and a FileReader object. Then you won't need all the other code and the loss of functionality. Losing all your data in the other fields when you add an attachment? Horrible! – Caspar Harmer Feb 27 '16 at 9:26
2

Your onclick event needs to be modified a little. It's not doing what you think it is. The behavior you're looking for on click of that commandButton is to call the JS to validate and then the JS will call the actionfunction to perform the POST of the form.

What's happening is you're executing the onclick script, which calls the actionfunction and then after that script is run (and the actionFunction starts to POST the form), control is returned to the button itself to finish its own click behavior - which is to submit the form it is contained in. You need to prevent this form submission by the button because you only want the JavaScript to do this work.

You need to return false; from the onclick event to prevent that default behavior of the button submitting the form. (Don't forget to add the semi-colon after the warning() function call too.)

<apex:commandButton value="Attach to Case" onclick="warning(); return false;" />
1

Ok, this is not directly answering the question - it's sidestepping it - but it will solve the issue of losing all your data.

Use in <input> of type="file" + a FileReader object + an <actionFunction>:

HTML:

<input type="file" id="fileInput" onchange="saveFile(this)" />

Javascript:

<script type="text/javascript">
    function saveFile(obj){
      if (obj.files && obj.files[0]) {
        var reader = new FileReader();
        reader.onload = function (e) {
            var data = e.target.result;    
            var mimeType = data.split(",")[0].split(":")[1].split(";")[0];
            var rawData = data.replace(/^data:image\/.*;base64,/, "");
            saveFileAF(rawData, "{!recId}");
        }
        reader.readAsDataURL(obj.files[0]);
      }
    }                        
</script>

Visualforce:

<apex:actionFunction name="saveFileAF" 
     action="{!saveFile}" rerender="none" >
    <apex:param name="base64File" value=""/>
    <apex:param name="fileName" value=""/>
</apex:actionFunction>

The controller method is pretty much the same - you just have to retrieve the params from the page or bind the actionfunction params to getters.

I took this code from a working example that I'm currently using. It may have errors, as I made changes to simplify it for you.

Good luck.

  • I'm sure this is a far better option; however, me and JavaScript don't exactly get along. I was kicking myself relying on JavaScript to display the message as it is. My primary concern with this solution is that I don't fully understand it. I may end up implementing it eventually but I have to go with Mark Pond's answer for now as it directly answered the question. – gNerb Feb 28 '16 at 19:09
  • Another note: developer.mozilla.org/en-US/docs/Web/API/FileReader shows that this is supported only in IE 10+. We still have users relying on IE versions as early as 8 for software compatibility reasons. – gNerb Feb 28 '16 at 19:11
  • Good point - still, if you find yourself wanting to explore this option further, there is a way around this (possibly not an easy one if you and JavaScript don't get along :) ) - look here: stackoverflow.com/questions/5397991/… – Caspar Harmer Feb 28 '16 at 19:15
-1

You can use JQuery something like this: [flow_recors] could be the area you want to refresh, for example a pageBlock or a table.

 <apex:actionFunction name="refreshMyPanel" reRender="flow_records" />


 $('#your_funtion').click(funtion(event)){
      refreshMyPanel();
 });

it could help.

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.