The component has a mandatory attribute named "sobjId" - this is the id of the sobject that the uploaded files will be attached to. Note that you can't use the name "id" for the attribute, as this is a standard attribute that allows the component to be identified by other components in the page.
The Attachment sobjects backing the input file elements are stored in a list in the controller that is initialised in the constructor to contain a single element. Clicking the Add More button causes another five Attachment sobjects to be appended to the list. As the user can choose to fill in the attachments in any order (e.g. just populating the last two elements), we can't simply insert the attachments when the save button is clicked, as that will attempt to insert the empty attachments that the user hasn't supplied details for. Thus we iterate the list and only insert those Attachments that have the Body field populated.
Note that there is no field for the user to input the name of the Attachment - I'm using the filename for the this, as the filename extension gives a browser a good chance of automatically opening the attachment when it is downloaded.
The Done button simply takes the user back to the view page for the object matching the supplied id attribute.
There's a couple of wrinkles when dealing with file uploads:
- When the page initially renders with one file chooser, if you choose a file and then click the Add More button, the chooser will not remember the file that you chose. This is browser behaviour, as it is not possible to prefill a file chooser under any circumstances - otherwise malicious pages could upload files from your hard disk without your consent.
- The body of the uploaded file is stored as a Blob. To unit test code that handles file uploading, you can create a Blob from a String using the valueof method:
Blob bodyBlob=Blob.valueOf('Unit Test Attachment Body');
Note that when using the example page, you'll need to supply the id of an existing sobject (Account, Opportunity etc).