Show TOC

Persisting Settings in Property BagsLocate this document in the navigation structure

You can use property bags to persist any key-value pairs in order to store settings for your application.

Using property bags, you can persist page settings in the following scopes:

  • Personalization: User-specific settings (These settings supersede Customizing and Configuration settings.)
  • Customizing: Client-specific settings (These settings supersede Configuration settings, but can be superseded by Personalization settings.)
  • Configuration: System-wide settings (These settings can be superseded by Customizing and Personalization settings.)

Example

The following example page shows a test application that stores a single property (count) in a bag in order to count from 0 to 100 while saving intermediate results.

An interval timer is used with a delay of 10 milliseconds. The purpose of this interval timer is to simulate user events which trigger the need for saving a property to a bag. The timer calls step(oBag) with the appropriate bag, increments the count property by one and requests a save operation. In order to avoid consuming too many resources in the browser and in the back-end system, we stop after counting to 100.

The following example uses an existing page named ZOO and a property bag that is attached to this page and named TODO. Before testing this example, you have to create a page and change the name of the page accordingly in the code below. Also adapt the name of the bag as required.

<!DOCTYPE html>
<!-- Copyright (c) 2013 SAP AG, All Rights Reserved -->
<html>
  <head>
    <meta http-equiv="Content-Type" content="text/html;charset=UTF-8"/>
    <meta http-equiv="X-UA-Compatible" content="IE=9"/>
    <title>Personalization Service HOW-TO</title>

    <!-- TODO remove data-sap-ui-loglevel for productive usage! -->
    <script id="sap-ui-bootstrap"
      data-sap-ui-loglevel="INFO"
      src="/sap/public/bc/ui5_ui5/resources/sap-ui-core.js">
    </script>

    <script src="/sap/public/bc/ui2/services/sap/ui2/srvc/bag.js"></script>
    <script src="/sap/public/bc/ui2/services/sap/ui2/srvc/error.js"></script>
    <script src="/sap/public/bc/ui2/services/sap/ui2/srvc/factory.js"></script>
    <script src="/sap/public/bc/ui2/services/sap/ui2/srvc/page.js"></script>
    <script src="/sap/public/bc/ui2/services/sap/ui2/srvc/pbs.js"></script>
    <script src="/sap/public/bc/ui2/services/sap/ui2/srvc/utils.js"></script>

    <script  type="text/javascript">
      "use strict";
      /*global alert, clearInterval, jQuery, sap, setInterval */
      var  oFactory, oIntervalId, oPageBuildingService,
        sPageId = "ZOO", //TODO choose your page ID
        sUrl = "/sap/opu/odata/UI2/PAGE_BUILDER_PERS/";

      /**
       * Dummy error handler using alert(); change this for productive use!
       *
       * @param {string} sMessage
       */
      function onError(sMessage) {
        alert(sMessage);
      }

      /**
       * Save the given bag, either immediately or later on, as soon as saving is possible again.
       *
       * @param {sap.ui2.srvc.Bag} oBag
       */
      function save(oBag) {
        var sProperty;

        if (oBag.$saving) {
          oBag.$dirty = true;
          return;
        }

        sProperty = oBag.getProperty("count");
        oBag.$saving = true;
        oBag.save(
          function () {
            oBag.$saving = false;
            jQuery.sap.log.info("You have been saved", sProperty);

            if (oBag.$dirty) {
              oBag.$dirty = false;
              save(oBag);
            }
          },
          function (oMap) {
            oBag.$saving = false;
            alert(JSON.stringify(oMap));
          }
        );
      }

      /**
       * Do one step of incrementing the count.
       *
       * @param {sap.ui2.srvc.Bag} oBag
       */
      function step(oBag) {
        var sProperty = oBag.getProperty("count"),
          iProperty = parseInt(sProperty, 10);

        if (iProperty < 100) {
          // increment count and save it
          iProperty += 1;
          oBag.setProperty("count", String(iProperty));
          save(oBag);
        } else {
          // stop counting, be nice to the backend ;-)
          clearInterval(oIntervalId);
        }
      }

      /**
       * Page wrapper has been created, start counting from 0.
       *
       * @param {sap.ui2.srvc.Page} oPage
       */
      function onPageCreated(oPage) {
        var sBagId = "TODO",
          oBag = oPage.getBag(sBagId);

        oBag.setProperty("count", "0");
        oIntervalId = setInterval(step.bind(null, oBag), 10);
      }

      oPageBuildingService = new sap.ui2.srvc.PageBuildingService(sUrl, onError);
      oFactory = new sap.ui2.srvc.Factory(oPageBuildingService);
      oFactory.createPage(sPageId, onPageCreated, onError, true);
      // flow continues in onPageCreated()
    </script>
  </head>
  <body>
    This page is intentionally left blank.
  </body>
</html>

The main code creates a new sap.ui2.srvc.PageBuildingService with a base URL and an error handler. Depending on the base URL, the settings are read from and written to one of the following scopes:

Base URL Description
/sap/opu/odata/UI2/PAGE_BUILDER_PERS/ User-specific personalization
/sap/opu/odata/UI2/PAGE_BUILDER_CUST/ Client-specific customizing
/sap/opu/odata/UI2/PAGE_BUILDER_CONF/ System-wide configuration

Then, a sap.ui2.srvc.Factory is created based on the page building service, and createPage is called in order to create a page wrapper object with a specific ID. The data for the page is loaded from the page building service. Upon success or failure of this backend call, the corresponding handler function is invoked. The last parameter to createPage() makes sure that only the needed parts of the page are loaded, including all its bags, but excluding any embedded CHIP instances.

Once the page data has been loaded, getBag() is called on the page wrapper to access a certain bag, creating it if needed. On the bag, setProperty() is called to set the value of a property, again creating it if needed. Note that the property value is a string and needs to be converted.

Saving a Property Bag

The save() method must not be called on a bag while a previous save() operation is still running. It is up to the application to deal with this.

In the example above, it is not required to store each increment of the counter individually. It is sufficient to store the intermediate result now and then, and to make sure that the result is properly stored at the end. This is achieved in the following way: Like any JavaScript object, an sap.ui2.srvc.Bag instance can be augmented with additional properties. The example above uses a $ prefix to avoid collisions with possible future enhancements of the sap.ui2.srvc.Bag class.

The save(oBag) method in the example above keeps track of two states on the level of individual bags:

  • It needs to know whether a save() operation is currently running.
  • It needs to remember the calls which could not trigger an immediate save() operation.

If a save operation could not be triggered immediately, the bag is marked as $dirty and needs to be saved later, at the earliest opportunity.

In the example above, we intentionally do not trigger another save() operation in case of failure. However, this needs to be decided case-by-case for each implementation. In case of success, the $dirty flag is checked, and another save() operation is triggered if needed.

The jQuery.sap.log.info() call adds some logging to the browser's console. Note that it remembers the intermediate result at the moment the save() method is invoked - this is usually different from the current state at the time the operation has finished.