Skip to Content
Technical Articles

Your first SAP Analytics Cloud Custom Widget – Part 2

This is part 2 of the Your first SAP Analytics Cloud Custom Widget tutorial series. As usual, the final results are on github, for your perusal.  If you have not been following since the beginning, I suggest going back to the introduction post and start from the beginning.  Last time, we got our first widget into SAP Analytics Cloud. The only problem is that the widget is hardcoded HTML. That is probably not going to be interesting for most situations and we’re going to want to investigate the different options for making our widget dynamic.

This post is a shortish one. We won’t add any new SAP Analytics Cloud specific functionality. Instead, we’ll make some JavaScript tweaks in preparation for further steps. We are doing this in a separate post, so as to quarantine the non-SAP Analytics Cloud specific steps and make the series easier to follow. Today, we’re going to do four things:

  • We’ll get rid of the hardcoded html in the shadow DOM
  • We will begin building up our shadow DOM at runtime, via JavaScript. This rendering will be done in the redraw() method, and we will put in the basic structure.
  • In later episodes, we’ll implement and use official widget properties for the tag type and text. When we actually render the widget, we’ll be using JavaScript variables. We will to our web component tag class now and later, we’ll attach these variables to official widget properties.
  • We won’t need to make any functional changes to the metadata JSON, but we will want to keep the ID, new instance prefix and tag up to date.

Start by updating the numeric suffix of the web component tag. Let’s call it com-sap-sample-helloworld2

 

Shadow DOM update

This is easy. We’ll simply empty out the shadow DOM contents. We’ll still attach it in the constructor() callback method, but the template for the shadow DOM will be empty.

    let tmpl = document.createElement('template');
    tmpl.innerHTML = `
    `;

 

New Variables in the constructor() Callback

We’ll declare three new variables in the constructor() callback.

  • _tagContainer – This is a utility variable, used in the redraw() for holding our HTML tag in the DOM. We don’t declare it with a value, so it is null when created in the constructor. Put a pin in that and we’ll circle back to it later.
  • _tagType – this will be a string, containing the header tag type, “h1”, “h2” or “h3”. The header tag created will be whatever the value of this variable is when redraw() is called. If we were writing productive code, we’d be a LOT more defensive here and enforce that the value of this string is restricted to these values. In the name of simplicity and keeping our focus on the SAP Analytics Cloud moving parts, we’ll skip the defensive programming and simple use the value.
  • _tagText – This will hold that the text that we’ll put into the shadow DOM when redraw() is called.
constructor() {
    super(); 
    this._shadowRoot = this.attachShadow({mode: "open"});
    this._shadowRoot.appendChild(tmpl.content.cloneNode(true));
    this._tagContainer;
    this._tagType = "h1";
    this._tagText = "Hello World";
}

 

redraw()

This is the method that we’ll actually use to draw the widget. We’ll do a few things:

  • We’ll delete the existing widget and redraw it from scratch. Recall that _tagContainer is where we keep track of the HTML that we added to the shadow DOM, but it is null when declared. If something has been added to the shadow DOM, it won’t be null. Therefore, if it is not null, let’s get rid of it.
  • Fill _tagContainer by creating a document element. Use the value of _tagType for the element.
  • Create a text node with the text in _tagText.
  • Add the text node to the header element and add the header element to the document.
  • Make sure that this code is only run when _tagText is not Null.
redraw(){
    if (this._tagText != null){
        if (this._tagContainer){
            this._tagContainer.parentNode.removeChild(this._tagContainer);
        }

        var shadow = window.getSelection(this._shadowRoot);
        this._tagContainer = document.createElement(this._tagType);
        var theText = document.createTextNode(this._tagText);    
        this._tagContainer.appendChild(theText); 
        this._shadowRoot.appendChild(this._tagContainer);
    }
}

We won’t need to alter redraw() any more in this series, so you are done with it! Host the new version of the file, so host it wherever you want and contineue to the metadata.

 

Metadata Updates

We don’t need to do anything serious in the metadata JSON file. Please index the numeric suffixes of name, id, and newInstancePrefix. Inside the webcomponents element, update the the tag element to match the .js file (likely com-sap-sample-helloworld2). Update the url element to point to the newly hosted file.

{
	"name": "Hello World Step 2",
	"description": "The first step in creating a minamilistic KPI tile",
	"eula": "",
	"vendor": "",
	"license": "",
	"id": "com.sap.sample.helloworld2",
	"newInstancePrefix": "HelloWorld2",
	"version": "0.0.1",
	"icon": "data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAABAAAAAQCAMAAAAoLQ9TAAAAA3NCSVQICAjb4U/gAAAAb1BMVEX///+ZmZl4dXdBPj9hYGGOjpE6ODo8OjwvLC0lISIpJSaMiooyLzH/cjMxLi9GREb/ZSk2MzV9fX1MSks4NjcrJyn/WR9ycnJRT1AtKiv/TRVdXF1ra2v7VCfJyMk+PD6tra+rqqtUUlU0MTNqaGpjxDg2AAAAAXRSTlMAQObYZgAAAAlwSFlzAAAOxAAADsQBlSsOGwAAAKhJREFUGNM9z9EagiAMBeDpEGkWNAGhqFTq/Z8xwK/+q7PtZgeg6npEMcBPJ0d1Kmg6ZnFGRZcLESnR7tpoouuVSCPPZYHWee+XxTsrvQeYQrwV97tL5uZigMeoqucTUSnWEVBX4fWaW2BYz1W3bXsLDPldcD8MoYZ3glmMjNbGLJk5igDgnLTGHazdAPo1Gdms2bZXhRmbMuNR5rNWJuX075sMYg57jV94IQ2Xqt1atQAAAABJRU5ErkJggg==",
	"webcomponents": [
        {
			"kind": "main",
			"tag": "com-sap-sample-helloworld2",
            "url": "https://davidhstocker.github.io/SAC_CustomWidget_HelloWorld_2/webcomponent.js",
            "integrity": "",
            "ignoreIntegrity" : true
        }
    ],
	"properties": {
	},
	"methods": {
	},
	"events": {
	}
}

Upload the new metadata JSON file. Add your new widget to your test app and give it a try. It is still static, but ready to be made dynamic. Next time, we’ll add widget properties and make the widget configurable from the styling panel.

/
4 Comments
You must be Logged on to comment or reply to a post.
  • Hello David Stocker,

     

    I followed your blog and created a custom widget the same as mentioned in the blog.  but am getting an error while inserting the custom widget into the application.

    Could you please help me out what the reason for that?

     

    Thanks,

    Bhargava

    /
    • That’s usually due to a bug in the JavaScript.  Open your browser’s debugger and click on the sources tab.  Look in the packages in the navigation pane on the right and locate the domain where you hosted the JavaScript.  You should be able to debug and find it there.  The version on Github, linked at the top of this post, is a working example.

       

      /