You would like to place a text box on the canvas, allow a user to capture multiple lines of free text based on a certain datasource dimension index and save the comments. Then you would like to retrieve these comments when the datasource is set to these dimension filter values.
This is a common requirement where you do not wish to capture comments by line item but rather commentary which is applicable to the entire dashboard but might be relevant for a certain level of datasource dimension granularity which is not mandatory to include all dimensions.
The difference between this kind of commentary approach and using the embedded model BPC advanced DSO is that you do not need to create an input-ready BW planning query. In fact you do not need a data source at all if you simply want to save comments at an Design Studio application level.
The solution for this use case has already been written by Jeroen van der A in his blog https://blogs.sap.com/2016/06/24/how-to-save-comments-in-design-studio/
However, if you are anything like me you probably need an even more in-depth “dummies guide to comments with bookmarks”. If you seem to be missing the FRAGMENTGALLERY_1 it’s because you’ve opened an application in mode “m”, so let’s go step-for-step.
This Design Studio application contains a text area where the user is able to capture any length of text, use the “Save” button to save the comment which adds a bookmark to the listbox below. Then the user is able to select any of the listbox bookmark ID’s and press the “Load” button to load the comment back into the text area.
Step-by-step dummies guide to comments via bookmarks
1. Logon to Design Studio and create a blank application with template “SAPUI5 m”
2. Drag and drop the PANEL component onto the canvas.
This step is simple but it’s an important concept to understand. Although we are using Design Studio bookmarks as a way of saving comments they still remain fundamentally a user navigational state bookmark which means that firstly they only act directly on container components. In order to save a comment (text box) we need the panel container first into which we put the text box. It is not possible to bookmark the text box directly.
Secondly bookmarks save all the information about the state of the container and it’s content, which is why they recover any text information in a text box within the container, but it also means that if you save a bookmark of a container thats properties have subsequently changed and you reload that bookmark, it will overwrite your current properties.
As a simple example let’s assume you create a panel with the width and height set at 487 and 224, as in our example below. You add the text box, capture text and save the bookmark. Then you change your screen design and alter the width and height and perhaps you even move the panel into another container. In this case when you reload that bookmark the screen will revert to the original status of the bookmark.
This is the fundamental basis of how bookmarks are being used to save text box content but bear in mind they are still bookmarks with much more capabilities.
3. Drag and drop the “Text Area” component into the panel
4. Now add the following components so they are positioned like the screenshot
- Button 1 – Change text to read “Save”
- Button 2 – Change text to read “Load”
- Listbox 1
- Listbox 2
- Listbox 3
I’ve made the first listbox width 280 because we are going to display the bookmark id in this listbox and it’s a long key which will probably still overflow the width but at least we can see most of it.
5. Now let’s add the code to save the comment and display the saved bookmarks details in the three list boxes.
The only code that is needed to save the bookmark is the “saveBookmark” statement with the first two parameters i.e. which container to save (PANEL_1) with which key (“MYKEY001”). The title and description are optional.
You can use ctrl-space to lookup the first statement command “Bookmark” and then use the context-sensitive help by pressing “.” to complete the rest of the statement.
However, take note of the restrictions for the first parameter, the bookmark group identifier, which is our key. If you plan to use the member id’s of a dimension from a datasource to construct a key they often have a character like a dash “-” or a space and can easily be less than 8 characters in length. These are not allowed in the bookmark groupidentifier so you may need to convert some of this text into a bookmark compatible format.
Also take note why it is called a GROUPIDENTIFIER. Usually a key means something unique and can’t be used twice. However, in terms of bookmarks you can use the same groupidentifier (GID) more than once because this GID is not the bookmark ID. The bookmark ID is a technical number allocated by the system to the bookmark. The technical bookmark ID is unique but is automatically allocated to the bookmark when saving. This means, in our example, that you can capture a comment and save, then capture a new comment and save again using the same GID and the system will save 2 comments for the same GID. As a developer you will need to manage this behavior. If you only wish to keep the latest comment then when saving you must first delete all prior bookmark ID’s saved on the same GID.
For our example we will keep all the bookmark ID’s and show how they can be loaded back.
6. Add script logic to display the technical bookmark ID’s
Before we execute this application, which in this state will run and save our bookmarks with various text captured, let’s add the code which will reflect the technical bookmark ID’s which the system assigns to the SAVE, otherwise you will not see anything happening. We use the statement “getAllBookmarkInfos” to retrieve the technical bookmark ID’s which is returned as an array.
The next code returns all the bookmarks for a groupidentifier (our key) into an array which we loop around and fill the listboxes so we can see them.
Note how the returned array of bookmark ID’s is an array of PortableFragmentBookmarkInfo with a record structure containing our title, description, container, groupidentifier and imageUrl if we had used it.
7. Now lets capture 3 comments, pressing the “SAVE” button after each comment and noticing how the list boxes grow with the new bookmark ID after each save even though they are all on the same groupidentifier ID.
On the left text is captured, multiple lines until the box is full and flows over to a scroll bar so we can demonstrate that there is no limit to the length of the text. Once the save button is pressed the right-hand screen demonstrates how the bookmark ID is added to the listbox together with the title and description that we assigned to the group identifier when we saved.
Now with multiple saves the listboxes grow with each new bookmark that is added. The text box is manually cleared and a new comment written and saved each time.
8. Add the script to retrieve the bookmarks. We are going to do this by clicking on the bookmark ID in the first listbox and using this selection to load that ID back.
Select the “LOAD” button and add the script to the “On click” event.
The code itself is a little unceremonious as we have already retrieved the bookmark ID’s in the array.
Save the application and re-run it. Since we have not written a startup script to load any available bookmarks the boxes all start in a blank state. However, capture some new text (this will be the fourth comment on this groupidentifier), and press “SAVE”. Our code on the SAVE button then saves the fourth comment and loads all 4 bookmarks into the listboxes.
Now select any of the bookmark ID’s in the first listbox and press the “LOAD” button to see the comments retrieved.
9. Closing comment
This completes the explanation of the mechanics behind the bookmark commentary solution. You can see how it is now possible to combine the groupidentifier key with a combination of text derived from the dimension members of a datasource and capture and save comments at any level, node or base member, simply by constructing your own groupidentifier key subject to the restrictions for bookmarks.