How to Create a SAPUI5 Custom Multi-Uploader with Table

Introduction

File upload features are essential for web applications that need to handle user documents, photos, and other files. SAPUI5 provides robust tools to create these functionalities. This article explains how to develop a custom multi-file uploader with a table display using SAPUI5.

Prerequisites

To follow along with this tutorial, you should have a basic understanding of JavaScript and experience with the SAPUI5 framework.

Creating the Uploader Control

The custom control will be a combination of UI elements that allow users to select files, view a list of the selected files, and upload them to a server.

Define the Control and Metadata: Begin by defining the control and its metadata properties like uploadPath and baseUrl. This metadata will also include events such as filesSelected and uploadStarted.

 

sap.ui.define(
[
“sap/ui/core/Control”,
“sap/m/Table”,
“sap/m/Column”,
“sap/m/Text”,
“sap/m/ColumnListItem”,
“sap/m/Input”,
“sap/m/Button”,
“sap/ui/core/Icon”,
],
function (
Control,
Table,
Column,
Text,
ColumnListItem,
Input,
Button,
Icon
) {
“use strict”;

return Control.extend(“project1.control.Uploader”, {
metadata: {
properties: {
uploadButtonText: {
type: “string”,
defaultValue: “Upload All”,
},
triggerButtonText: {
type: “string”,
defaultValue: “Choose Files”,
},
uploadPath: { type: “string”, defaultValue: “/upload” },
baseUrl: {
type: “string”,
defaultValue: “http://example.com”,
},
},
aggregations: {
_table: {
type: “sap.m.Table”,
multiple: false,
visibility: “hidden”,
},
_uploadButton: {
type: “sap.m.Button”,
multiple: false,
visibility: “hidden”,
},
_triggerButton: {
type: “sap.m.Button”,
multiple: false,
visibility: “visible”,
},
},
events: {
filesSelected: {},
uploadStarted: {},
},
},
});
}
);

 

Initialize the Control: The initialization phase will set up the table and buttons required for file selection and upload actions.

 

init: function () {
var oTable = new Table({
columns: [
new Column({ header: new Text({ text: “File Name” }) }),
new Column({ header: new Text({ text: “Status” }) }),
new Column({ header: new Text({ text: “Preview” }) }),
new Column({
header: new Text({ text: “Description” }),
}),
],
});

var oUploadButton = new Button({
text: this.getProperty(“uploadButtonText”),
press: this._onUploadAll.bind(this),
});

var oTriggerButton = new Button({
text: this.getProperty(“triggerButtonText”),
press: () => {
document
.getElementById(this.getId() + “-fileUploader”)
.click();
},
});

this.setAggregation(“_table”, oTable);
this.setAggregation(“_uploadButton”, oUploadButton);
this.setAggregation(“_triggerButton”, oTriggerButton);
},​

 

Setters for Properties: Provide setter methods for properties to customize the uploader’s behavior, such as setting the base URL or upload path dynamically.

 

setBaseUrl: function (sPath) {
this.setProperty(“baseUrl”, sPath);
return this;
},

setUploadButtonText: function (sText) {
this.setProperty(“uploadButtonText”, sText, true);
var oUploadButton = this.getAggregation(“_uploadButton”);
if (oUploadButton) {
oUploadButton.setText(sText);
}
return this;
},

setTriggerButtonText: function (sText) {
this.setProperty(“triggerButtonText”, sText, true);
var oTriggerButton = this.getAggregation(“_triggerButton”);
if (oTriggerButton) {
oTriggerButton.setText(sText);
}
return this;
},

setUploadPath: function (sPath) {
this.setProperty(“uploadPath”, sPath);
return this;
},

 

Renderer Function

Define how the uploader will render in the DOM. Include hidden file input for selecting files and visible buttons for triggering the file selection dialog and uploading files.

 

renderer: function (oRm, oControl) {
oRm.write(“<div”);
oRm.writeControlData(oControl);
oRm.write(“>”);
oRm.write(
“<input type=’file’ multiple=’multiple’ id='” +
oControl.getId() +
“-fileUploader’ style=’display:none;’/>”
);
oRm.renderControl(oControl.getAggregation(“_triggerButton”));
oRm.renderControl(oControl.getAggregation(“_table”));
oRm.renderControl(oControl.getAggregation(“_uploadButton”));
oRm.write(“</div>”);
},

 

Handling File Selection

Create a method to handle changes in the file input. This method should update the table with file details and prepare them for upload.

 

 

onAfterRendering: function () {
var oFileInput = document.getElementById(
this.getId() + “-fileUploader”
);
if (oFileInput) {
oFileInput.removeEventListener(
“change”,
this._onFileChange.bind(this)
);
oFileInput.addEventListener(
“change”,
this._onFileChange.bind(this)
);
}
},

_onFileChange: function (oEvent) {
var aFiles = oEvent.target.files;
var oTable = this.getAggregation(“_table”);

var aFileData = [];

Array.from(aFiles).forEach(function (file) {
var oItem = new ColumnListItem({
cells: [
new Text({ text: file.name }),
new Text({ text: “Ready” }),
new Icon({
src: “sap-icon://attachment”,
size: “2rem”,
}),
new Input({ placeholder: “Enter description” }),
],
});
oTable.addItem(oItem);
aFileData.push({
file: file,
name: file.name,
});
});
this._uploadedFiles = aFileData;
this.fireEvent(“filesSelected”, { files: aFiles });
},

 

Uploading Files

Implement the upload functionality. This involves reading files from the table, creating a FormData object, and sending it to the server using a fetch request.

 

_onUploadAll: function () {
var oTable = this.getAggregation(“_table”);
var aItems = oTable.getItems();
var uploadPath = this.getProperty(“uploadPath”);
var baseUrl = this.getProperty(“baseUrl”);
var oFormData = new FormData();

this._uploadedFiles.forEach(function (item, index) {
var oDescription = aItems[index].getCells()[3].getValue();
oFormData.append(“files”, item.file, item.name);
oFormData.append(“descriptions”, oDescription);
});

var oRequest = () =>
fetch(`${baseUrl}${uploadPath}`, {
method: “POST”,
body: oFormData,
}).then(function (response) {
return response.json();
});
console.log(“Upload Path:”, uploadPath);
this.fireEvent(“uploadStarted”, {
request: oRequest,
});
},

 

Adding a Control in XML

We add a control in XML View using namespace and structure

 

 

<mvc:View controllerName=”project1.controller.View1″
xmlns:mvc=”sap.ui.core.mvc” displayBlock=”true”
xmlns=”sap.m”
xmlns:core=”sap.ui.core”
xmlns:custom=”project1.control”>
<Page id=”page” title=”{i18n>title}”>
<custom:Uploader uploadButtonText=”Upload” triggerButtonText=”Choose”
uploadPath=”/files” uploadStarted=”onUploadStarted” />
</Page>
</mvc:View>

 

Handling Uploads

Once the files are selected and the upload process is initiated, the onUploadStarted function plays a crucial role in managing the asynchronous upload operation. This function is triggered by the uploadStarted event, which also passes the upload request function as an event parameter.

 

sap.ui.define(
[“sap/ui/core/mvc/Controller”, “sap/m/MessageToast”],
function (Controller, MessageToast) {
“use strict”;

return Controller.extend(“project1.controller.View1”, {
onInit: function () {},
onUploadStarted: async function (oEvent) {
try {
var oResult = await oEvent.getParameter(“request”)();
MessageToast.show(“Request done”);
// do smth with response …
} catch (oError) {
MessageToast.show(oError?.message || “Request failed”);
}
},
});
}
);

 

Conclusion

With this control, integrating file upload functionalities into SAPUI5 applications becomes straightforward, enabling developers to manage file uploads efficiently. Additionally, the flexibility of this control allows for customization according to specific needs. Developers can freely modify the approach to use oData services for backend integration, opt to upload files individually for better control over each transaction, and also alter the display methods to better suit the user interface requirements. This adaptability makes it a robust solution for various file handling scenarios in SAPUI5 applications.

Thank you!

 

​ IntroductionFile upload features are essential for web applications that need to handle user documents, photos, and other files. SAPUI5 provides robust tools to create these functionalities. This article explains how to develop a custom multi-file uploader with a table display using SAPUI5.PrerequisitesTo follow along with this tutorial, you should have a basic understanding of JavaScript and experience with the SAPUI5 framework.Creating the Uploader ControlThe custom control will be a combination of UI elements that allow users to select files, view a list of the selected files, and upload them to a server.Define the Control and Metadata: Begin by defining the control and its metadata properties like uploadPath and baseUrl. This metadata will also include events such as filesSelected and uploadStarted. sap.ui.define(
[
“sap/ui/core/Control”,
“sap/m/Table”,
“sap/m/Column”,
“sap/m/Text”,
“sap/m/ColumnListItem”,
“sap/m/Input”,
“sap/m/Button”,
“sap/ui/core/Icon”,
],
function (
Control,
Table,
Column,
Text,
ColumnListItem,
Input,
Button,
Icon
) {
“use strict”;

return Control.extend(“project1.control.Uploader”, {
metadata: {
properties: {
uploadButtonText: {
type: “string”,
defaultValue: “Upload All”,
},
triggerButtonText: {
type: “string”,
defaultValue: “Choose Files”,
},
uploadPath: { type: “string”, defaultValue: “/upload” },
baseUrl: {
type: “string”,
defaultValue: “http://example.com”,
},
},
aggregations: {
_table: {
type: “sap.m.Table”,
multiple: false,
visibility: “hidden”,
},
_uploadButton: {
type: “sap.m.Button”,
multiple: false,
visibility: “hidden”,
},
_triggerButton: {
type: “sap.m.Button”,
multiple: false,
visibility: “visible”,
},
},
events: {
filesSelected: {},
uploadStarted: {},
},
},
});
}
); Initialize the Control: The initialization phase will set up the table and buttons required for file selection and upload actions. init: function () {
var oTable = new Table({
columns: [
new Column({ header: new Text({ text: “File Name” }) }),
new Column({ header: new Text({ text: “Status” }) }),
new Column({ header: new Text({ text: “Preview” }) }),
new Column({
header: new Text({ text: “Description” }),
}),
],
});

var oUploadButton = new Button({
text: this.getProperty(“uploadButtonText”),
press: this._onUploadAll.bind(this),
});

var oTriggerButton = new Button({
text: this.getProperty(“triggerButtonText”),
press: () => {
document
.getElementById(this.getId() + “-fileUploader”)
.click();
},
});

this.setAggregation(“_table”, oTable);
this.setAggregation(“_uploadButton”, oUploadButton);
this.setAggregation(“_triggerButton”, oTriggerButton);
},​ Setters for Properties: Provide setter methods for properties to customize the uploader’s behavior, such as setting the base URL or upload path dynamically. setBaseUrl: function (sPath) {
this.setProperty(“baseUrl”, sPath);
return this;
},

setUploadButtonText: function (sText) {
this.setProperty(“uploadButtonText”, sText, true);
var oUploadButton = this.getAggregation(“_uploadButton”);
if (oUploadButton) {
oUploadButton.setText(sText);
}
return this;
},

setTriggerButtonText: function (sText) {
this.setProperty(“triggerButtonText”, sText, true);
var oTriggerButton = this.getAggregation(“_triggerButton”);
if (oTriggerButton) {
oTriggerButton.setText(sText);
}
return this;
},

setUploadPath: function (sPath) {
this.setProperty(“uploadPath”, sPath);
return this;
}, Renderer FunctionDefine how the uploader will render in the DOM. Include hidden file input for selecting files and visible buttons for triggering the file selection dialog and uploading files. renderer: function (oRm, oControl) {
oRm.write(“<div”);
oRm.writeControlData(oControl);
oRm.write(“>”);
oRm.write(
“<input type=’file’ multiple=’multiple’ id='” +
oControl.getId() +
“-fileUploader’ style=’display:none;’/>”
);
oRm.renderControl(oControl.getAggregation(“_triggerButton”));
oRm.renderControl(oControl.getAggregation(“_table”));
oRm.renderControl(oControl.getAggregation(“_uploadButton”));
oRm.write(“</div>”);
}, Handling File SelectionCreate a method to handle changes in the file input. This method should update the table with file details and prepare them for upload.  onAfterRendering: function () {
var oFileInput = document.getElementById(
this.getId() + “-fileUploader”
);
if (oFileInput) {
oFileInput.removeEventListener(
“change”,
this._onFileChange.bind(this)
);
oFileInput.addEventListener(
“change”,
this._onFileChange.bind(this)
);
}
},

_onFileChange: function (oEvent) {
var aFiles = oEvent.target.files;
var oTable = this.getAggregation(“_table”);

var aFileData = [];

Array.from(aFiles).forEach(function (file) {
var oItem = new ColumnListItem({
cells: [
new Text({ text: file.name }),
new Text({ text: “Ready” }),
new Icon({
src: “sap-icon://attachment”,
size: “2rem”,
}),
new Input({ placeholder: “Enter description” }),
],
});
oTable.addItem(oItem);
aFileData.push({
file: file,
name: file.name,
});
});
this._uploadedFiles = aFileData;
this.fireEvent(“filesSelected”, { files: aFiles });
}, Uploading FilesImplement the upload functionality. This involves reading files from the table, creating a FormData object, and sending it to the server using a fetch request. _onUploadAll: function () {
var oTable = this.getAggregation(“_table”);
var aItems = oTable.getItems();
var uploadPath = this.getProperty(“uploadPath”);
var baseUrl = this.getProperty(“baseUrl”);
var oFormData = new FormData();

this._uploadedFiles.forEach(function (item, index) {
var oDescription = aItems[index].getCells()[3].getValue();
oFormData.append(“files”, item.file, item.name);
oFormData.append(“descriptions”, oDescription);
});

var oRequest = () =>
fetch(`${baseUrl}${uploadPath}`, {
method: “POST”,
body: oFormData,
}).then(function (response) {
return response.json();
});
console.log(“Upload Path:”, uploadPath);
this.fireEvent(“uploadStarted”, {
request: oRequest,
});
}, Adding a Control in XMLWe add a control in XML View using namespace and structure  <mvc:View controllerName=”project1.controller.View1″
xmlns:mvc=”sap.ui.core.mvc” displayBlock=”true”
xmlns=”sap.m”
xmlns:core=”sap.ui.core”
xmlns:custom=”project1.control”>
<Page id=”page” title=”{i18n>title}”>
<custom:Uploader uploadButtonText=”Upload” triggerButtonText=”Choose”
uploadPath=”/files” uploadStarted=”onUploadStarted” />
</Page>
</mvc:View> Handling UploadsOnce the files are selected and the upload process is initiated, the onUploadStarted function plays a crucial role in managing the asynchronous upload operation. This function is triggered by the uploadStarted event, which also passes the upload request function as an event parameter. sap.ui.define(
[“sap/ui/core/mvc/Controller”, “sap/m/MessageToast”],
function (Controller, MessageToast) {
“use strict”;

return Controller.extend(“project1.controller.View1”, {
onInit: function () {},
onUploadStarted: async function (oEvent) {
try {
var oResult = await oEvent.getParameter(“request”)();
MessageToast.show(“Request done”);
// do smth with response …
} catch (oError) {
MessageToast.show(oError?.message || “Request failed”);
}
},
});
}
); ConclusionWith this control, integrating file upload functionalities into SAPUI5 applications becomes straightforward, enabling developers to manage file uploads efficiently. Additionally, the flexibility of this control allows for customization according to specific needs. Developers can freely modify the approach to use oData services for backend integration, opt to upload files individually for better control over each transaction, and also alter the display methods to better suit the user interface requirements. This adaptability makes it a robust solution for various file handling scenarios in SAPUI5 applications.Thank you!   Read More Technology Blogs by Members articles 

#SAP

#SAPTechnologyblog

You May Also Like

More From Author