SOLVED

SPFX react web part: SharePoint List attachment displaying broken image when viewed

Brass Contributor

Hey all,

I have been attempting to attach a file/image via a form on a SPFx webpart (more specifically, via an <

<input type="file" /> tag). The file/image is displayed as a paperclip icon on the SharePoint list, but when I click into the list item to view the image, it displays a broken link. Note that this is a form that takes in leave requests. See the following for the arrangement of the steps :

 

 

// This is my interface with the required data needed for a leave request on ILeaveRequestForm.ts
export interface ILeaveRequestForm {
    request: [{
        Employee: string;
        StartDate: string;
        EndDate: string;
        LeaveType: string;
        Reason: string;
        Status: string;
    }];
    selectedLeaveType: string;
    Attachments: File;
}

 

 

 

// This is the initialized state on ILeaveRequestForm.tsx
const initialState: ILeaveRequestForm = {
    request: [{
        Employee: '',
        StartDate: '',
        EndDate: '',
        LeaveType: '',
        Reason: '',
        Status: 'Pending'
    }],
    selectedLeaveType: '',
    Attachments: new File([""], "", { type: "text/plain",})
};

 

 

 

// This is the markup in the render method
public render(): React.ReactElement<any> {
    <div className="form-row">
                    <div className="form-group col-md-12">
                        <label>Start Date&nbsp;<span className={styles.required}>*</span></label>
                        <input type="date" className="form-control" id="startDate" min={today.slice(0, 4) + "-01-01"} max={today.slice(0, 4) + "-12-31"} onBlur={this.validateWeekend} required />
                    </div>
                    <div className="form-group col-md-12">
                        <label>End Date&nbsp;<span className={styles.required}>*&nbsp;<small id="Message"></small></span></label>
                        <input type="date" className="form-control" id="endDate" min={today.slice(0, 4) + "-01-01"} max={today.slice(0, 4) + "-12-31"} onBlur={this.validateWeekend} required />
                    </div>
                    <div className="form-group col-md-12" id="fileBrowser2">
                        <label>Upload Schedule&nbsp;<span className={styles.required}>*</span></label>
                        <div className="custom-file">
                            <input type="file" className="custom-file-input" id="studyAttachment" onChange={this.handleFileUpload} required />
                            <label className="custom-file-label" id="fileName">Choose file</label>
                        </div>
                    </div>
                </div>
}

 

 

 

// This is the script to handle the upload and adding to SharePoint List
private handleFileUpload = (event) => {

        var file = event.target.value;
        var file2 = (document.getElementById("studyAttachment") as HTMLInputElement).files[0];

        var fileName = file.split("\\").pop();
        document.getElementById("fileName").innerHTML = fileName;

        var reader = new FileReader();
        var dataURL;
        reader.onload = () => {
            dataURL = reader.result;
            console.log(dataURL)
          };

          console.log("fileInfo: " + fileInfo);
          reader.readAsDataURL(file2);

        this.setState({ Attachments: new File([dataURL], file2.name, { type: file2.type }) });
    }

private handleSubmit = (event) => {
        event.preventDefault();

            var ptoStDtTime = $("#ptoStartDate").val() + "T" + $("#ptoStartTime").val();
            var ptoEdDtTime = $("#ptoEndDate").val() + "T" + $("#ptoEndTime").val();

            var data = {
                "Employee": this.props.currentUser,
                "LeaveType": this.state.selectedLeaveType,
                "StartDate": $("#startDate").val() != undefined ? $("#startDate").val() : ptoStDtTime,
                "EndDate": $("#endDate").val() != undefined ? $("#endDate").val() : ptoEdDtTime,
                "Reason": $("#reason").val() != undefined ? $("#reason").val() : '',
                "Status": "Pending",
                "Attachments": this.state.Attachments
            };

            //Log form data
            console.log(data);

            // Set correct absoluteUrl of SP site
            const url = this.props.url;
            let web = new Web(url);

            //Insert into SP List
            web.lists.getByTitle('Leave%20Request%20Form').items.add({
                Employee: data.Employee,
                StartDate: data.StartDate,
                EndDate: data.EndDate,
                LeaveType_x003a_Description: data.LeaveType,
                Reason: data.Reason,
                Status: data.Status
                //Attachments: data.Attachments
            }).then((iar: ItemAddResult) => {
                // this will add an attachment to the item we just created
                iar.item.attachmentFiles.add(data.Attachments.name, data.Attachments);

                //refresh page
                window.location.reload();
            }).catch(e => { console.error(e); });
    }

export default LeaveRequestForm;

 

 

Here are some images to outline the process:

 

Filling out Leave FormFilling out Leave Form

 

Saved list item with paperclip iconSaved list item with paperclip icon

 

Selected list item to click attachment to viewSelected list item to click attachment to view

 

After clicking attachment, broken image displaysAfter clicking attachment, broken image displays

 

 

Can anyone offer any assistance? Maybe I'm not understanding how to add attachments to a SharePoint List properly.

 

I also tried this method outlined here and I get the very same result: https://github.com/SharePoint/PnP-JS-Core/wiki/Working-With:-Attachments

3 Replies

@Yarrah 

 

Instead of reading the file as DataURL ,can you try using the method readAsArrayBuffer() with the reader object.

best response confirmed by Yarrah (Brass Contributor)
Solution

@O365Developer 

 

I tried your suggestion and it was not working out for me. I ended up doing some more in-depth research and testing and finally got it to work. 

 

For those who are probably experiencing the same issue, here is the working code:

NB:

1. The markup in the render method remained the same

2. The images with the steps remained the same except after clicking attachment, the image finally displays.

 

// This is my interface with the required data needed for a leave request on ILeaveRequestForm.ts
export interface ILeaveRequestForm {
    request: [{
        Employee: string;
        StartDate: string;
        EndDate: string;
        LeaveType: string;
        Reason: string;
        Status: string;
    }];
    selectedLeaveType: string;
    Attachments: File;
}

 

// This is the initialized state on ILeaveRequestForm.tsx
const initialState: ILeaveRequestForm = {
    request: [{
        Employee: '',
        StartDate: '',
        EndDate: '',
        LeaveType: '',
        Reason: '',
        Status: 'Pending'
    }],
    selectedLeaveType: '',
    Attachments: new File([""], "", { type: "",})
};

 

// This is the script to handle the upload and adding to SharePoint List
private handleFileUpload = (event) => {
        var file = event.target.value;
        var fileInfo = (document.getElementById("attachment") as HTMLInputElement).files[0];

        //Set file input with file name
        var fileName = file.split("\\").pop();
        document.getElementById("fileName").innerHTML = fileName;

        this.setState({ Attachments: fileInfo });
    }

private handleSubmit = (event) => {
        event.preventDefault();

        //Form validations
        if (this.validateLeaveTaken()) {
            event.preventDefault();
        }
        else {

            console.log(this.state.Attachments);
            var ptoStDtTime = $("#ptoStartDate").val() + "T" + $("#ptoStartTime").val();
            var ptoEdDtTime = $("#ptoEndDate").val() + "T" + $("#ptoEndTime").val();

            var data = {
                "Employee": this.props.currentUser,
                "LeaveType": this.state.selectedLeaveType,
                "StartDate": $("#startDate").val() != undefined ? $("#startDate").val() : ptoStDtTime,
                "EndDate": $("#endDate").val() != undefined ? $("#endDate").val() : ptoEdDtTime,
                "Reason": $("#reason").val() != undefined ? $("#reason").val() : '',
                "Status": "Pending",
                "Attachments": this.state.Attachments
            };

            //Log form data
            console.log(data);
            console.log("Attachment data: " + data.Attachments);

            // Set correct absoluteUrl of SP site
            const url = this.props.url;
            let web = new Web(url);

            //Insert into SP List
            web.lists.getByTitle('Leave%20Request%20Form').items.add({
                Employee: data.Employee,
                StartDate: data.StartDate,
                EndDate: data.EndDate,
                LeaveType_x003a_Description: data.LeaveType,
                Reason: data.Reason,
                Status: data.Status
            }).then((iar: ItemAddResult) => {
                //Upload attachment if any
                if (data.Attachments != null) {
                    var toUpload = data.Attachments;
                    var r = new FileReader();

                    r.onloadend = (e) => {
                        var dataItems = e.target.result;
                        iar.item.attachmentFiles.add(toUpload.name, dataItems).then(() => {
                            alert();
                        });
                    };

                    r.readAsArrayBuffer(toUpload);
                    console.log("iar: " + iar);
                }

                //refresh page
                window.location.reload();

            }).catch(e => { console.error(e); });
        }
    }

 

 Additionally, I tested with other file types such as word, excel, pdf, jpg and png and they all were accepted and uploaded to the SharePoint Attachments column in my list.

@Yarrah Can you please share the code? Thanks!

1 best response

Accepted Solutions
best response confirmed by Yarrah (Brass Contributor)
Solution

@O365Developer 

 

I tried your suggestion and it was not working out for me. I ended up doing some more in-depth research and testing and finally got it to work. 

 

For those who are probably experiencing the same issue, here is the working code:

NB:

1. The markup in the render method remained the same

2. The images with the steps remained the same except after clicking attachment, the image finally displays.

 

// This is my interface with the required data needed for a leave request on ILeaveRequestForm.ts
export interface ILeaveRequestForm {
    request: [{
        Employee: string;
        StartDate: string;
        EndDate: string;
        LeaveType: string;
        Reason: string;
        Status: string;
    }];
    selectedLeaveType: string;
    Attachments: File;
}

 

// This is the initialized state on ILeaveRequestForm.tsx
const initialState: ILeaveRequestForm = {
    request: [{
        Employee: '',
        StartDate: '',
        EndDate: '',
        LeaveType: '',
        Reason: '',
        Status: 'Pending'
    }],
    selectedLeaveType: '',
    Attachments: new File([""], "", { type: "",})
};

 

// This is the script to handle the upload and adding to SharePoint List
private handleFileUpload = (event) => {
        var file = event.target.value;
        var fileInfo = (document.getElementById("attachment") as HTMLInputElement).files[0];

        //Set file input with file name
        var fileName = file.split("\\").pop();
        document.getElementById("fileName").innerHTML = fileName;

        this.setState({ Attachments: fileInfo });
    }

private handleSubmit = (event) => {
        event.preventDefault();

        //Form validations
        if (this.validateLeaveTaken()) {
            event.preventDefault();
        }
        else {

            console.log(this.state.Attachments);
            var ptoStDtTime = $("#ptoStartDate").val() + "T" + $("#ptoStartTime").val();
            var ptoEdDtTime = $("#ptoEndDate").val() + "T" + $("#ptoEndTime").val();

            var data = {
                "Employee": this.props.currentUser,
                "LeaveType": this.state.selectedLeaveType,
                "StartDate": $("#startDate").val() != undefined ? $("#startDate").val() : ptoStDtTime,
                "EndDate": $("#endDate").val() != undefined ? $("#endDate").val() : ptoEdDtTime,
                "Reason": $("#reason").val() != undefined ? $("#reason").val() : '',
                "Status": "Pending",
                "Attachments": this.state.Attachments
            };

            //Log form data
            console.log(data);
            console.log("Attachment data: " + data.Attachments);

            // Set correct absoluteUrl of SP site
            const url = this.props.url;
            let web = new Web(url);

            //Insert into SP List
            web.lists.getByTitle('Leave%20Request%20Form').items.add({
                Employee: data.Employee,
                StartDate: data.StartDate,
                EndDate: data.EndDate,
                LeaveType_x003a_Description: data.LeaveType,
                Reason: data.Reason,
                Status: data.Status
            }).then((iar: ItemAddResult) => {
                //Upload attachment if any
                if (data.Attachments != null) {
                    var toUpload = data.Attachments;
                    var r = new FileReader();

                    r.onloadend = (e) => {
                        var dataItems = e.target.result;
                        iar.item.attachmentFiles.add(toUpload.name, dataItems).then(() => {
                            alert();
                        });
                    };

                    r.readAsArrayBuffer(toUpload);
                    console.log("iar: " + iar);
                }

                //refresh page
                window.location.reload();

            }).catch(e => { console.error(e); });
        }
    }

 

 Additionally, I tested with other file types such as word, excel, pdf, jpg and png and they all were accepted and uploaded to the SharePoint Attachments column in my list.

View solution in original post