Media download via the UploadCollection

The UI5-Framework provides an easy method for implementing up and download for media-entities via OData-Services with the sap.m.UploadCollection.

Requirements

  1. A correctly configured OData-Service with at least one Media-Entity.
  2. Redefinition and implementation of the GET_STREAM, CREATE_STREAM ( only for uploads) and the DEFINE-Method of the provider classes.
  3. UI5-Version of this example: 1.76

Media-Entity

Let’s say we have the following metadata-config for our MediaEntity in ODataV2:

<EntityType Name="Document" m:HasStream="true" sap:content-version="1">
<Key>
<PropertyRef Name="ID"/>
</Key>
<Property Name="ID" Type="Edm.String" Nullable="false" MaxLength="32" sap:unicode="false" sap:label="ID" sap:creatable="false" sap:updatable="false"/>
<Property Name="DocumentName" Type="Edm.String" Nullable="false" MaxLength="254" sap:unicode="false" sap:label="Document Name"/>
<Property Name="DocumentType" Type="Edm.String" Nullable="false" MaxLength="128" sap:unicode="false" sap:label="Document Type"/>
<Property Name="Content" Type="Edm.String" Nullable="false" sap:unicode="false" sap:label="Content"/>
<Property Name="ArchivId" Type="Edm.String" Nullable="false" MaxLength="2" sap:unicode="false" sap:label="Archiv ID"/>
<Property Name="ArchivDocId" Type="Edm.String" Nullable="false" MaxLength="40" sap:unicode="false" sap:label="Archiv Document ID"/>
<Property Name="ArchivDocType" Type="Edm.String" Nullable="false" MaxLength="20" sap:unicode="false" sap:label="Archiv Document Typ"/></EntityType>
			

As previously said, a requirement is the correct implementation of the STREAM-Methods (CREATE_STREAM, GET_STREAM and DEFINE)

Now we want do add functionalities for downloading documents from the DocumentSet into our App. To make this happen, we need the sap.m.UploadCollection-Control.

View-Implementation

First of all we need to declare and implement the UploadCollection with the aggregated UploadCollectionItem.

<UploadCollection id="detail_uploadcollection" items="{fileModel>/files}" mode="MultiSelect" uploadEnabled="false"						uploadButtonInvisible="true" selectionChange="onDocumnetSelectionChange">						<toolbar>
    <OverflowToolbar>
        <ToolbarSpacer/>
        <Button enabled="{viewModel>/downloadEnabled}" text="{i18n>btn_download}" press="onDownloadDocuments" type="Transparent"/>
        <UploadCollectionToolbarPlaceholder/>
        </OverflowToolbar>
</toolbar>
<items>
    <UploadCollectionItem documentId="{ID}" url="{path: 'ID', formatter: '.formatUrl'}" fileName="{DocumentName}" mimeType="{DocumentType}" enableEdit="false" enableDelete="false" visibleDelete="false" visibleEdit="false"/>
</items>
</UploadCollection>

The UploadCollectionItem has the property url, which needs do be filled with a valid URL to our Document. In this case we take the actual URL to the Document in combination with our Service-URL. This URL is not provided as a standard property of our Entity so we need to build this via a detour.

By using a custom formatter, we create a valid ULR to our Media-Entry.

A valid sample URL that points to our Media-Entry would be: https://<hostname>:<port>/sap/opu/odata/<servicename>/DocumentSet(ID=’566F112400211EDA9CD176726FCF0230′)/$value

We want to use exactly this URL for each UploadCollectionItem. This can be done via AggregationBinding. When we have done this, the URL including the $value parameter, returns the Media-Stream for our Entry.

Controller-Implementation

We need a custom formatter for each Property-Binding for the url-Property in our UploadCollectionItem-Aggregation. In this formatter we get the actual service url of our OData-Model, add the URI (KEY) of the aggregated Element and add the $value parameter.

formatUrl: function (sSrId, sSeqnr) {
			let sUrl = this.getModel().sServiceUrl;
			sUrl += "/" + this.getModel().createKey("DocumentSet", {
				ID: sSrId
			});
			sUrl += "/$value";
			return sUrl;
		},

After implementing the code snipped, we get correct UploadCollectionItems that open the Media-Etry in a seperate Browser-Tab.

If we press the name of the Document, a Browser-Tab opens.

But w also want to select multiple documents and bundle the download so that we dont have to download them seperately.

First we need to implement an event handler for the selectionChanged-Event of the UploadCollection to dynamically alter the enabled-Property of the Download-Button. The property enabled of the Button is controlled via a JSONModel and Property-Binding.

onDocumnetSelectionChange: function (oEvent) {
			let oUploadCollection = oEvent.getSource();
			if (oUploadCollection.getSelectedItems().length > 0) {
				this._oViewModel.setProperty("/downloadEnabled", true);
			} else {
				this._oViewModel.setProperty("/downloadEnabled", true);
			}
		},

Finally we need to implement the event habdler for the button-press-Event. In this handler we need to download the selected UploadCollectionItems.

onDownloadDocuments: function (oEvent) {
			let oUploadCollection = this.getView().byId("detail_uploadcollection"),
				aSelectedItems = oUploadCollection.getSelectedItems();
			for (var i = 0; i < aSelectedItems.length; i++) {
				oUploadCollection.downloadItem(aSelectedItems[i], true);
			}
		},

As a final step we could deploy the Application onto the Backend/onPremise-System.

Now we can download the selected Items by using the Download-Button. The download-Function of the UploadCollection uses the url-Property of the UploadCollectionItem to get the valid URL pointing to our Media-Entry.

In conclusion we can see that the UI5-Framework is providing an easy way to add up- and download functionalities to our UI5-App. And by using this apporach, Media-Handling is easy to implement into our applications.