Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Original file line number Diff line number Diff line change
Expand Up @@ -21,7 +21,7 @@ describe("c-file-upload", () => {
// test
// verify select files button is shown
const selectButton = element.shadowRoot.querySelector("lightning-input");
expect(selectButton.label).toBe("Pick file to upload");
expect(selectButton.label).toBe("Select file to upload");
// verify upload button is not shown
const uploadButton = element.shadowRoot.querySelector("button.slds-button");
expect(uploadButton).toBeNull();
Expand Down
82 changes: 45 additions & 37 deletions force-app/main/default/lwc/fileUpload/fileUpload.html
Original file line number Diff line number Diff line change
@@ -1,49 +1,57 @@
<template>
<h1>File Upload</h1>

<div>
<lightning-input
<!-- File selection controls. Always displayed.
Set `accept="*/*"` to allow uploads of any type of file. -->
<div>
<lightning-input
type="file"
name="fileUploader"
label="Pick file to upload"
multiple="true"
accept="*/*"
onchange={handleInputChange}
label="Select file to upload"
multiple="false"
accept="image/*"
onchange={handleFilesInputChange}
>
</lightning-input>
</div>

<!-- Currently komaci only supports the if:true= instead of the new lwc:if directive -->
<div if:true={fileName}>
<p>Selected file:</p>
<p>{fileName}</p>
<div class="inputs">
<lightning-input
type="text"
label="Title"
value={titleValue}
onchange={handleTitleInputChange}
></lightning-input>
<lightning-input
type="text"
label="Description"
value={descriptionValue}
onchange={handleDescriptionInputChange}
></lightning-input>
</div>
<button
class="slds-button slds-button_brand slds-var-m-top_medium"
disabled={uploadingFile}
onclick={handleUploadClick}
>
<label>Upload</label>
</button>
</div>
<!-- If a file is selected, display additional input controls. -->
<div if:true={fileName}>

<!-- Currently komaci only supports the if:true= instead of the new lwc:if directive -->
<div if:true={errorMessage}>
<lightning-card title="Error">
<div class="card-body">{errorMessage}</div>
</lightning-card>
<!-- Show the filename (read-only) -->
<p>Selected file:</p>
<p>{fileName}</p>

<!-- Form fields for upload details -->
<div class="inputs">
<lightning-input
type="text"
label="Title"
value={titleValue}
onchange={handleTitleInputChange}
></lightning-input>
<lightning-input
type="text"
label="Description"
value={descriptionValue}
onchange={handleDescriptionInputChange}
></lightning-input>
</div>

<!-- Button to actually do the upload (enqueued as a draft) -->
<button
class="slds-button slds-button_brand slds-var-m-top_medium"
disabled={uploadingFile}
onclick={handleUploadClick}
>
<label>Upload</label>
</button>
</div>

<!-- If there are errors, show them here -->
<div if:true={errorMessage}>
<lightning-card title="Error">
<div class="card-body">{errorMessage}</div>
</lightning-card>
</div>
</template>
54 changes: 37 additions & 17 deletions force-app/main/default/lwc/fileUpload/fileUpload.js
Original file line number Diff line number Diff line change
@@ -1,13 +1,14 @@
import { LightningElement, api, wire, track } from "lwc";
import { LightningElement, api, track, wire } from "lwc";
import { ShowToastEvent } from "lightning/platformShowToastEvent";
import {
createContentDocumentAndVersion,
createRecord,
} from "lightning/uiRecordApi";
// Imports for forced-prime ObjectInfo metadata work-around
import { getObjectInfos } from "lightning/uiObjectInfoApi";
import { ShowToastEvent } from "lightning/platformShowToastEvent";
import CONTENT_DOCUMENT_LINK from "@salesforce/schema/ContentDocumentLink";
import CONTENT_DOCUMENT from "@salesforce/schema/ContentDocument";
import CONTENT_VERSION from "@salesforce/schema/ContentVersion";
import CONTENT_DOCUMENT_LINK from "@salesforce/schema/ContentDocumentLink";

export default class FileUpload extends LightningElement {
@api
Expand All @@ -28,13 +29,16 @@ export default class FileUpload extends LightningElement {
@track
errorMessage = "";

// Object metadata are required for creating records in offline. The wire adapter is added here to ensure the content metadata are primed.
// Object metadata, or "ObjectInfo", is required for creating records
// while offline. Use the getObjectInfos adapter to "force-prime" the
// necessary object metadata. This is a work-around for the static analyzer
// not knowing enough about the file object schema.
@wire(getObjectInfos, {
objectApiNames: [CONTENT_DOCUMENT_LINK, CONTENT_DOCUMENT, CONTENT_VERSION],
objectApiNames: [CONTENT_DOCUMENT, CONTENT_VERSION, CONTENT_DOCUMENT_LINK],
})
objectMetadata;

// This getter is only used for local processing. It does not need to be enabled for offline caching.
// Getter used for local-only processing. Not needed for offline caching.
// eslint-disable-next-line @salesforce/lwc-graph-analyzer/no-getter-contains-more-than-return-statement
get fileName() {
// eslint-disable-next-line @salesforce/lwc-graph-analyzer/no-unsupported-member-variable-in-member-expression
Expand All @@ -45,7 +49,8 @@ export default class FileUpload extends LightningElement {
return undefined;
}

handleInputChange(event) {
// Input handlers
handleFilesInputChange(event) {
this.files = event.detail.files;
this.titleValue = this.fileName;
}
Expand All @@ -58,20 +63,22 @@ export default class FileUpload extends LightningElement {
this.descriptionValue = event.detail.value;
}

// Restore the UI to its default state to allow uploading
// Restore UI to default state
resetInputs() {
this.files = [];
this.titleValue = "";
this.descriptionValue = "";
this.errorMessage = "";
}

// Handle the user uploading a file
// Handle uploading a file, initiated by user clicking Upload button
async handleUploadClick() {
// Make sure we're not already uploading something
if (this.uploadingFile) {
return;
}

// Make sure we have something to upload
const file = this.files && this.files[0];
if (!file) {
return;
Expand All @@ -80,21 +87,30 @@ export default class FileUpload extends LightningElement {
try {
this.uploadingFile = true;

// Create a Content Document and Version for the file
// effectively uploading it
// Create a ContentDocument and related ContentDocumentVersion for
// the file, effectively uploading it
const contentDocumentAndVersion = await createContentDocumentAndVersion({
title: this.titleValue,
description: this.descriptionValue,
fileData: file,
});
console.log(
"ContentDocument and ContentDocumentVersion records created.",
);

// If component is run in a record context (recordId is set), relate
// the uploaded file to that record
if (this.recordId) {
const contentDocumentId = contentDocumentAndVersion.contentDocument.id;

// Create a ContentDocumentLink (CDL) to associate the uploaded file
// to the Files Related List of the target recordId
await this.createCdl(this.recordId, contentDocumentId);
// to the Files related list of the target recordId
await this.createContentDocumentLink(this.recordId, contentDocumentId);
}

// Status and state updates
console.log("File upload created and enqueued.");
this.notifySuccess();
this.resetInputs();
} catch (error) {
console.error(error);
Expand All @@ -104,8 +120,8 @@ export default class FileUpload extends LightningElement {
}
}

// Create the link between the new file upload and the target record
async createCdl(recordId, contentDocumentId) {
// Create link between new file upload and target record
async createContentDocumentLink(recordId, contentDocumentId) {
await createRecord({
apiName: "ContentDocumentLink",
fields: {
Expand All @@ -114,10 +130,14 @@ export default class FileUpload extends LightningElement {
ShareType: "V",
},
});
console.log("ContentDocumentLink record created.");
}

notifySuccess() {
this.dispatchEvent(
new ShowToastEvent({
title: "Success",
message: "File attached",
title: "Upload Successful",
message: "File enqueued for upload.",
variant: "success",
}),
);
Expand Down
10 changes: 8 additions & 2 deletions force-app/main/default/lwc/fileUpload/fileUpload.js-meta.xml
Original file line number Diff line number Diff line change
@@ -1,6 +1,7 @@
<?xml version="1.0" encoding="UTF-8" ?>
<?xml version="1.0" encoding="UTF-8"?>
<LightningComponentBundle xmlns="http://soap.sforce.com/2006/04/metadata">
<apiVersion>57.0</apiVersion>
<description>Example of offline-capable file uploads.</description>
<apiVersion>58.0</apiVersion>
<isExposed>true</isExposed>
<targets>
<target>lightning__RecordPage</target>
Expand All @@ -10,5 +11,10 @@
<targetConfig targets="lightning__RecordAction">
<actionType>ScreenAction</actionType>
</targetConfig>
<targetConfig targets="lightning__RecordPage">
<supportedFormFactors>
<supportedFormFactor type="Small" />
</supportedFormFactors>
</targetConfig>
</targetConfigs>
</LightningComponentBundle>