Skip to Content
Technical Articles
Author's profile photo Abhimanyu Lagishetti

Implementing Attachments in UI5

Introduction

This blog helps UI5/Fiori developers understand sap.m.uploader.UploadSet UI Element in detail.

Problem

The SAP UI5 Demo site explains the UploadSet sample application. However, the  site can not explain how it works with a back-end system.

Solution

Below is the step by step working example of the UploadSet UI element that I have implement. Hope this helps clarify many questions related to UploadSet.

Back-end Gateway Service Implementation

Build a Gateway Project, create an entity for attachment attributes shown below.

Gateway%20Project

Gateway Project

Mark the entity as Media

Re-define Define method of the MPC Extension class to mark the Mimetype  field as content type.

  method DEFINE.
    super->define( ).

    data: lo_entity TYPE REF TO /iwbep/if_mgw_odata_entity_typ,

    lo_property TYPE REF TO /iwbep/if_mgw_odata_property.
    lo_entity = model->get_entity_type( iv_entity_name = 'Attachment' ).
    IF lo_entity IS BOUND.
     lo_property = lo_entity->get_property( iv_property_name = 'Mimetype').
     lo_property->set_as_content_type( ).

     lo_property = lo_entity->get_property( iv_property_name = 'Erdat' ).
     lo_property->/iwbep/if_mgw_odata_annotatabl~create_annotation( 'sap' )->add(
       iv_key = 'display-format' iv_value = 'Date' ).
    ENDIF.

  endmethod.

Its time to implement the Data Provider class. Starting with re-defining method /IWBEP/IF_MGW_APPL_SRV_RUNTIME~CREATE_STREAM.

this method is called when an file is being attached. The most important information we need here is the content of the file, MIME type, filename, Key ( against which we are going to save this attachment ). We are making use of importing parameter iv_slug to get some of the information. We will know how to pass this information from UI when we code for UI5.

  method /IWBEP/IF_MGW_APPL_SRV_RUNTIME~CREATE_STREAM.
    DATA ls_attach      TYPE ZUI_ATTACHMENTS_S.
    DATA lv_xstring     TYPE xstring.
    DATA lr_attachments TYPE REF TO zcl_ut_ui5_attachments.
*    READ TABLE it_key_tab ASSIGNING FIELD-SYMBOL(<fs_key>) INDEX 1.

    SPLIT iv_slug AT ',' INTO ls_attach-filename
                              ls_attach-ref_guid
                              ls_attach-obj_name.

    ls_attach-mimetype  = is_media_resource-mime_type.
    ls_attach-erdat     = sy-datum.
    ls_attach-ernam     = sy-uname.

 

lf_data = is_media_resource-value.

** All the attachment information needed to save the file is obtained
** Now its time to save it to database/file system. Below code does that.
CREATE OBJECT lr_attachments.
ls_attach-guid  = lr_attachments->create_attachment( 
                     exporting i_attach = ls_attach
                     iv_content = lf_data
                  ).

** Return the etntity back to the caller
copy_data_to_ref( EXPORTING is_data = ls_attach
                  CHANGING  cr_data = er_entity ).

 

Implement method /IWBEP/IF_MGW_APPL_SRV_RUNTIME~GET_STREAM to download the file

  method /IWBEP/IF_MGW_APPL_SRV_RUNTIME~GET_STREAM.
    data ls_stream  type ty_s_media_resource.
    DATA lr_attachments TYPE REF TO zcl_ut_ui5_attachments.
    DATA ls_attach      TYPE zui_attachments.
    DATA ls_header      type ihttpnvp.
    DATA lv_guid        TYPE guid_32.
** Read the Key Information to obtain the file details
    READ TABLE it_key_tab INTO DATA(ls_key_tab) INDEX 1.
    IF sy-subrc <> 0.
      RETURN.
    ENDIF.
    lv_guid = ls_key_tab-value.

** Once the Key for the attachment is fetched. Its time to read the content
** from database/file system wherever it is stored
    CREATE OBJECT lr_attachments.
    lr_attachments->read_attachment( EXPORTING i_guid = lv_guid
                                    IMPORTING es_attach_data = ls_attach
                                              ev_content     = ls_stream-value ).

** Send back the attachment content to the caller.
    ls_header-name = 'Content-Disposition'.
    CONCATENATE 'attachment; filename="' ls_attach-filename '"' INTO ls_header-value.
    set_header( is_header = ls_header ).
    ls_stream-mime_type = ls_attach-mimetype.
    copy_data_to_ref( exporting is_data = ls_stream   changing  cr_data = er_stream ).

  endmethod.

 

Implement GET_ENTITYSET method to read all the attachment information associated to a particular document. ( RefGuid is the field that identifies all the attachments associated with it )

  method ATTACHMENTSET_GET_ENTITYSET.
    DATA lv_ref_guid  type guid_32.
    DATA lr_attachments TYPE REF TO zcl_ut_ui5_attachments.

** Get the RefGuid value to read its associated attachments
    read table it_filter_select_options INTO data(ls_filter) INDEX 1.
    IF sy-subrc = 0.
      READ TABLE ls_filter-select_options INTO data(ls_options)
           INDEX 1.
      IF sy-subrc = 0.
        lv_ref_guid = ls_options-low.
      ENDIF.
    ENDIF.
    CHECK lv_ref_guid IS NOT INITIAL.
*** Your own logic to read the attachments information.
    CREATE OBJECT lr_attachments.
    TRY.
    lr_attachments->get_all_attachment( exporting i_ref_guid = lv_ref_guid
                                        importing rt_attachment = DATA(lt_attach) ).

    SORT lt_attach BY erdat.

** Fill up the return entity
    LOOP AT lt_attach INTO DATA(ls_attach).
      APPEND INITIAL LINE TO et_entityset ASSIGNING FIELD-SYMBOL(<ls_entityset>).
      <ls_entityset>-filename = ls_attach-filename.
      <ls_entityset>-erdat      = ls_attach-erdat.
      <ls_entityset>-created_by = ls_attach-created_by.
      <ls_entityset>-guid       = ls_attach-guid.

    ENDLOOP.
    CATCH ZCX_ATTACHMENT.

    ENDTRY.
  endmethod.

 

Front-End Implementation

This UI5 code works from UI5 version 1.90.0. We are going to implement Attachments using sap.m.upload.UploadSet UI element.

Here is the XML code for the attachments view.

<mvc:View controllerName="test.ztest.controller.View1" xmlns:mvc="sap.ui.core.mvc" displayBlock="true" xmlns="sap.m"
	xmlns:core="sap.ui.core" xmlns:upload="sap.m.upload">
	<Shell id="shell">
		<App id="app">
			<pages>
				<Page id="idPage">
					<upload:UploadSet id="idAttach" showIcons="true" uploadEnabled="true" terminationEnabled="true"
						uploadUrl="/sap/opu/odata/sap/ZATTACHMENTS_SRV/AttachmentSet" instantUpload="true" items="{path: 'oModelAttach>/items' }"
						beforeUploadStarts="onBeforeUploadStarts" uploadCompleted="onUploadComplete">
						<upload:items>
							<upload:UploadSetItem fileName="{oModelAttach>fileName}" visibleRemove="true" removePressed="onRemovePressed">
								<upload:attributes>
									<ObjectAttribute title="File Description" text="{oModelAttach>fileName}"/>
								</upload:attributes>
							</upload:UploadSetItem>
						</upload:items>
					</upload:UploadSet>
				</Page>
			</pages>
		</App>
	</Shell>
</mvc:View>

Controller code to Read the existing attachments for a document ( which is RefGuid in our case )

			this.getOwnerComponent().getModel().read("/AttachmentSet", {
				filters: [new Filter("RefGuid", FilterOperator.EQ, "1234")],
				success: function (oData) {
					var json = new JSONModel([]);
					json.items = [];

					for (var i = 0; i < oData.results.length; i++) {
						var item = {
							Guid: oData.results[i].Guid,
							fileName: oData.results[i].Filename,
							meddiaType: oData.results[i].Mimetype,
							url: "/sap/opu/odata/sap/ZATTACHMENTS_SRV/AttachmentSet('" + oData.results[i].Guid + "')/$value",
							uploadState: "Complete",
							CreatedBy: oData.results[i].CreatedBy,
							Erdat: oData.results[i].Erdat,
							selected: false
						};
						json.items.push(item);
					}
					this.getView().getModel("oModelAttach").setData(json);

				}.bind(this),
				error: function (oError) {
					sap.m.MessageToast.show("Error occured reading data");
				}
			});

instantUpload property of UploadSet starts sending the file as soon we choose file or drag and drop on to UI element. We need to send the RefGuid ( Document number, other information if needed  ) along with the request. Here comes the use of iv_slug that we have learnt while implementing DPC_EXT. I am using a comma separated list of fields in slug.

We are making use of beforeUploadStarts event of UploadSet to pass that information.

onBeforeUploadStarts: function (oEvent) {
        var oHeaderItem = oEvent.getParameter("item"),
        slugVal = oHeaderItem.getFileName() + ",1234,ZSD_SAMPLES";
	oHeaderItem.removeAllStatuses();
	oHeaderItem.addHeaderField(new sap.ui.core.Item({
		key: "slug",
		text: slugVal
	}));
	oHeaderItem.addHeaderField(new sap.ui.core.Item({
		key: "x-csrf-token",
		text: this.getOwnerComponent().getModel().getSecurityToken()
	}));
}

Finally, Implementing onUploadComplete event to complete the upload and setAttachmentModel to read the attachments for a particular document (RefGuid in our case)

onUploadComplete: function (oEvent) {
	var oStatus = oEvent.getParameter("status"),
		oItem = oEvent.getParameter("item"),
		oUploadSet = this.getView().byId("idAttach");
	if (oStatus && oStatus !== 201) {
		oItem.setUploadState("Error");
		oItem.removeAllStatuses();
	} else {
		oUploadSet.removeIncompleteItem(oItem);
		this.setAttachmentModel();
	}
},
setAttachmentModel: function () {
	this.getOwnerComponent().getModel().read("/AttachmentSet", {
		filters: [new Filter("RefGuid", FilterOperator.EQ, "1234")],
		success: function (oData) {
			var json = new JSONModel([]);
			json.items = [];

			for (var i = 0; i < oData.results.length; i++) {
				var item = {
					Guid: oData.results[i].Guid,
					fileName: oData.results[i].Filename,
					meddiaType: oData.results[i].Mimetype,
					url: "/sap/opu/odata/sap/ZATTACHMENTS_SRV/AttachmentSet('" + oData.results[i].Guid + "')/$value",
					uploadState: "Complete",
					CreatedBy: oData.results[i].CreatedBy,
					Erdat: oData.results[i].Erdat,
					selected: false
				};
				json.items.push(item);
			}
			this.getView().getModel("oModelAttach").setData(json);
	             }.bind(this),
		error: function (oError) {
			sap.m.MessageToast.show("Error occured reading data");
		}
	});
}

 

Let’s see how it works

You can click on upload/ drag and drop files on to the UI element to upload. You can see the status of the uploading file.

Conclusion

The key point here while building this application is to know how to pass the additional parameters to the back-end with the help of slug header parameter from the front-end and how to handle it in the back-end.

 

References

API Reference: https://sapui5.hana.ondemand.com/#/api/sap.m.upload.UploadSet

Sample in Demo site: https://sapui5.hana.ondemand.com/#/entity/sap.m.upload.UploadSet

 

Hope this blog is helpful for you. Feel free to comment/suggest, like, and share.

 

Assigned Tags

      1 Comment
      You must be Logged on to comment or reply to a post.
      Author's profile photo Cuong Luc Dinh
      Cuong Luc Dinh

      Hi Abhimanyu Lagishetti,

      Thanks for blog, I'm using Service with Vocabulary-Based Annotations, so there is no option "media" for the entity type, do you know how I can use UploadSet for my application?

      Thanks & Best Regards,

      Dinh Cuong Luc