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.

WizardStep – Hide counter or title

Sometimes you come across requirements that can not always be solved with a „setProperty“, so this requirement too:

Hide counter

The customer requests that the numbering of the WizardSteps should be hidden. Every SAPUI5 developer knows that this doesn’t work out of the box, unlike to hide the „nextStep“ buttons.

these numbers should be hidden

So let’s start the developer tools and have a look at the headlines of the individual WizardSteps and how they are structured. We can see that these numbers are calculated and inserted by the framework at runtime:

developer tools

Here we can see that the numbers are inserted in a CSS-class called „.sapMWizardStepTitle::before“ in the „content“ section.

Go to the „style.css“-file in your project and override this CSS-class (webapp/css/style.css):

.sapMWizardStepTitle::before{
     content: ""!important;
}

We do nothing but override the number with an empty string. This is the result:

wizard step wihtout numbering

Hide titles

The same we want to do with the titles in each WizardStep.

Unfortunately if we just set the „title“ property to an empty string so the titles also disappear in the wizard header:

„title“ property in each wizard step set to an empty string
no titles in header and content

Of course we want to prevent that, we just want to hide the headings in the individual steps.

Now that we know that there is a CSS class „.sapMWizardStepTitle“, we can simply hide it:

.sapMWizardStepTitle{
     display: none!important;
}

And as a result, we have now hidden our headings in the individual steps, but not in the header:

titles hidden