8

Is there a html equivalent of

    <div id="file">
        <apex:inputFile value="{!attachment.body}" filename="{!attachment.name}" id="file" title="Upload Attachment" styleclass="fileType"/> 
    </div>

Or perhaps a JS equivalent? I need to add this (or functionality very similar to this) dynamically an unknown amount of times to my page.

Would anyone have any sugestions?

EDIT

sf.dev suggested

 <label>Select file: <input type="file" name="imagefile" accept="image/jpeg, image/png"> 
 </label>       
 <input type="submit" value="upload">

how would I pass

'value="{!attachment.body}" filename="{!attachment.name}"' 

with that input? They don't seem to be recognised if I just add them.

9
  • Have you tried creating a List<Attachment> in your controller and using an apex:repeat to render enough apex:inputFile for the number in your list? If the number of apex:inputFile is dynamic during the page's lifespan then you can wrap your repeat in an apex:outputPanel and reRender it when the required number of apex:inputFile is changed. Commented Apr 17, 2014 at 16:03
  • Thanks Alex, but I need to insert it into the DOM using jQuery, so I'm afraid all apex elements are out of the question...
    – Daft
    Commented Apr 17, 2014 at 16:06
  • Ok, I was afraid of that. Cheers Alex
    – Daft
    Commented Apr 17, 2014 at 16:09
  • In that case you won't be able to make use of the merge fields ({!attachment.body} and {!attachment.name}). If you go down the route of 'pure' HTML then you will have to do the uploading yourself, the easiest way to do this is using the AJAX Toolkit, but you could also do it with JavaScript Remoting or apex:actionFunction. Why do you have to insert them using jQuery? Commented Apr 17, 2014 at 16:10
  • Could you update the required amount of apex:inputFile using JavaScript and an apex:actionFunction which updates the number required in your controller and then triggers a reRender? Commented Apr 17, 2014 at 16:11

3 Answers 3

6

You can use standard HTML input tags to achieve this, and the AJAX Toolkit to actually upload the attachments.

Here is a basic example.

First you need somewhere to select your files and something to start off the upload:

<input id="file-input" type="file" name="file"/>
<input type="button" value="Upload" onclick="uploadFile();"/>

Then you need to initilise the AJAX Toolkit:

<script type="text/javascript">
    var __sfdcSessionId = '{!GETSESSIONID()}';
</script>
<script src="/soap/ajax/29.0/connection.js" type="text/javascript"></script>

Then on the JavaScript side of things you'll want to add this function to an onClick event somewhere (perhaps an Upload button), or even to the input onChange event if you want an instant upload:

function uploadFile()
{       
    var input = document.getElementById('file-input');
    var parentId = // Your ID here, I suggest using a merge field to get this

    var filesToUpload = input.files;

    for(var i = 0, f; f = filesToUpload[i]; i++)
    {
        var reader = new FileReader();     

        // Keep a reference to the File in the FileReader so it can be accessed in callbacks
        reader.file = f; 

        reader.onerror = function(e) 
        {
            switch(e.target.error.code) 
            {
                case e.target.error.NOT_FOUND_ERR:
                    alert('File Not Found!');
                    break;
                case e.target.error.NOT_READABLE_ERR:
                    alert('File is not readable');
                    break;
                case e.target.error.ABORT_ERR:
                    break; // noop
                default:
                    alert('An error occurred reading this file.');
            };
        };     

        reader.onabort = function(e) 
        {
            alert('File read cancelled');
        };

        reader.onload = function(e) 
        {
            var att = new sforce.SObject("Attachment");
            att.Name = this.file.name;
            att.ContentType = this.file.type;
            att.ParentId = parentId;

            att.Body = (new sforce.Base64Binary(e.target.result)).toString();

            sforce.connection.create([att],
            {
                onSuccess : function(result, source) 
                {
                    if (result[0].getBoolean("success")) 
                    {
                        console.log("new attachment created with id " + result[0].id);
                    } 
                    else 
                    {
                        console.log("failed to create attachment " + result[0]);
                    }
                }, 
                onFailure : function(error, source) 
                {
                    console.log("An error has occurred " + error);
                }
            });
        };

        reader.readAsBinaryString(f);
    }
}
6
  • Thanks a lot Alex! I've added this code but I'm getting the following error in message in Chrome when I try to upload an image. Any suggestions? Uncaught TypeError: Failed to execute 'readAsBinaryString' on 'FileReader': The argument is not a Blob. But the file is still appearing on screen so I think it's working. I'm just wondering how I would now post this to Salesforce?
    – Daft
    Commented Apr 18, 2014 at 9:10
  • 1
    @Daft Apologies, I typed that up from memory last night and didn't quite get it right (and missed a key step - initialising the AJAX Toolkit). The call to sforce.connection.create actually creates the record and you should get a message back in your log with the ID. If you need to do more complex work with the file within the JavaScript then change the behavior in the onSuccess and onFailure callbacks. Commented Apr 18, 2014 at 9:56
  • Cheers Alex! Really appreciate the assistance!
    – Daft
    Commented Apr 18, 2014 at 10:00
  • 1
    @Daft I've updated the code sample by the way to fix the Blob error so you can delete your other question :) Commented Apr 18, 2014 at 10:06
  • 1
    Cheers again Alex, really helpful answer! Pity I can only give it 1 upvote!
    – Daft
    Commented Apr 22, 2014 at 10:52
3
 <label>Select file: <input type="file" name="imagefile" accept="image/jpeg, image/png"> 
 </label>       
 <input type="submit" value="upload">
0
3

You can create a VF component to render the tags multiple times on your page. Bob Buzzard has a great blog article about this with sample code

http://bobbuzzard.blogspot.co.nz/2011/01/uploading-multiple-attachments-via.html

1
  • Cheers Jim! But it's close to the deadline and I gotta work with what I've already built! Appreciate the link though!
    – Daft
    Commented Apr 17, 2014 at 15:18

You must log in to answer this question.

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