Show TOC

Step 7: Adding a Comments SectionLocate this document in the navigation structure

In this step, we extend the product detail view by adding a feature allowing to add comments to the product.

Preview
Figure 1: Comments section added to the detail page
Coding

You can view and download all files in the Explored app in the Demo Kit under Worklist App - Step 7.

webapp/view/Object.view.xml

<mvc:View
   controllerName="myCompany.myApp.controller.Object"
   xmlns:mvc="sap.ui.core.mvc"
   xmlns:semantic="sap.m.semantic"
   xmlns:form="sap.ui.layout.form"
   xmlns="sap.m">
   <semantic:FullscreenPage
      id="page"
      busy="{objectView>/busy}"
      busyIndicatorDelay="{objectView>/delay}"
      navButtonPress="onNavBack"
      showNavButton="true"
      title="{i18n>objectTitle}">
      <semantic:content>
         ...
         <Panel
            class="sapUiContentPadding"
            headerText="{i18n>ObjectSupplierTabTitle}">
             ...
         </Panel>
         <Panel
            class="sapUiContentPadding"
            headerText="{i18n>ObjectCommentsTabTitle}">
            <content>
               <FeedInput post="onPost"/>
               <List
                  id="idCommentsList"
                  noDataText="{i18n>ObjectCommentNoData}"
                  showSeparators="Inner"
                  items="{
                     path: 'productFeedback>/productComments',
                     sorter: {
                        path: 'date',
                        descending: true
                     }
                  }">
                  <FeedListItem
                     info="{productFeedback>type}"
                     text="{productFeedback>comment}"
                     timestamp="{productFeedback>date}"/>
               </List>
            </content>
         </Panel>

      </semantic:content>
      <semantic:sendEmailAction>
         <semantic:SendEmailAction
            id="shareEmail"
            press="onShareEmailPress"/>
      </semantic:sendEmailAction>
   </semantic:FullscreenPage>
</mvc:View>

Below the already existing panel, we add another panel that will serve as a container for our comments section. Inside the new panel we add a sap.m.FeedInput control and attach an event handler onPost for the post event. This control will render an input field and a button which allow users to post comments. The event handler we registered will be implemented below.

Below the FeedInput control, we add a list with all existing comments. The items aggregation of the list is bound to the /productComments property of the named model productFeedback that we will create below. All comments shall be displayed in descending order based on their publishing date. Therefore, we also configure a sorter for our items in the list.

The template for each row is a FeedListItem control. We configure the FeedListItem to simply display the date of the post, the text of the post itself, and the type of the post.

webapp/controller/Object.controller.js

...
/*global location*/
sap.ui.define([
   "myCompany/myApp/controller/BaseController",
   "sap/ui/model/json/JSONModel",
   "sap/ui/core/routing/History",
   "myCompany/myApp/model/formatter",
   "sap/ui/core/format/DateFormat",
   "sap/ui/model/Filter",
   "sap/ui/model/FilterOperator"

], function(BaseController, JSONModel, History, formatter, DateFormat, Filter, FilterOperator) {
   "use strict";
   return BaseController.extend("myCompany.myApp.controller.Object", {
      formatter: formatter,
      ...
      _onBindingChange: function(oEvent) {
         ...
         // Update the comments in the list
         var oList = this.byId("idCommentsList");
         var oBinding = oList.getBinding("items");
         oBinding.filter(new Filter("productID", FilterOperator.EQ, sObjectId));
      },
      /**
      * Updates the model with the user comments on Products.
      * @function
      * @param {sap.ui.base.Event} oEvent object of the user input
      */
      onPost: function (oEvent) {
         var oFormat = DateFormat.getDateTimeInstance({style: "medium"});
         var sDate = oFormat.format(new Date());
         var oObject = this.getView().getBindingContext().getObject();
         var sValue = oEvent.getParameter("value");
         var oEntry = {
             productID: oObject.ProductID,
             type: "Comment",
             date: sDate,
             comment: sValue
         };        
         // update model
         var oFeedbackModel = this.getModel("productFeedback");
         var aEntries = oFeedbackModel.getData().productComments;
         aEntries.push(oEntry);
         oFeedbackModel.setData({
            productComments : aEntries
         });
      }

   });
});

First, we add three new dependencies to the controller. We need these dependencies because we want to create a filter for the list and because we format the date and time of each post.

Whenever the binding of the detail view changes, we want to make sure that the comments for the current product are displayed. Therefore, we change the private function _onBindingChange and update the filter of the list that displays the comments by getting a reference to the binding of the items aggregation of our list and calling the filter() API afterwards. The filter is passed on to the filter() API. We use the productID as fiilter criterium, because we only want comments for a specific product.

Next, the event handler for the post event of the FeedInput is implemented. In the onPost handler, we create a new entry object that contains all data we want to store in our model. This data is the productId, the type of the post (hard-coded in our example), the current date in a medium date format, and the comment itself. The comment is retrieved from the event object. The productId is determined by calling getObject() on the view’s binding context.

Finally, the new entry is added to the named model called productFeedback. This model does not exist yet, so let’s create it next.

webapp/model/models.js

sap.ui.define([
   "sap/ui/model/json/JSONModel",
   "sap/ui/Device"
], function(JSONModel, Device) {
   "use strict";
   return {
      createDeviceModel: function() {
         var oModel = new JSONModel(Device);
         oModel.setDefaultBindingMode("OneWay");
         return oModel;
      },   
      createCommentsModel: function() {
         return new JSONModel({ productComments : [] });
      }

   };
});

In both the object view (detail page) as well as in the corresponding controller we used a named model called productFeedback. In our example this model is a simple JSONModel. It is created in the function createCommentsModel() in the model.js file. As you can see above, the function simply returns a new instance of a JSONModel with a simple data object. The property productComments is an empty array and it will be updated every time someone posts a new comment.

However, this model is not yet accessible throughout our app. Let’s fix this next.

webapp/Component.js

sap.ui.define([
   "sap/ui/core/UIComponent",
   "sap/ui/Device",
   "myCompany/myApp/model/models",
   "myCompany/myApp/controller/ErrorHandler"
], function(UIComponent, Device, models, ErrorHandler) {
   "use strict";
   return UIComponent.extend("myCompany.myApp.Component", {
      ...
      init: function() {
         // call the base component's init function
         UIComponent.prototype.init.apply(this, arguments);

         // initialize the error handler with the component
         this._oErrorHandler = new ErrorHandler(this);

         // set the device model
         this.setModel(models.createDeviceModel(), "device");
         
         // set the product feedback model
         this.setModel(models.createCommentsModel(), "productFeedback");


         // create the views based on the url/hash
         this.getRouter().initialize();
      },
      ...
   });
});

Now it’s time to make the named model productFeedback available to our app. Therefore, just change the init function of our Component.js file by calling our createCommentsModel() method and setting the returned model on the component. After this, our model is accessible in our app.

webapp/i18n/i18n.properties

...
#Comments tab title
ObjectCommentsTabTitle=Comments

#No comments text
ObjectCommentNoData=No Comments


#~~~ Footer Options ~~~~~~~~~~~~~~~~~~~~~~~
...

Now add the new texts to our i18n.properties file and you’re done.

You can test the new features by navigating to the details page of any given product. After that, just create a new comment for that product and post it.