Technical Articles
SAP Analytics Cloud Barcode Scanner Custom Widget
In this blog, I will demonstrate how to create a barcode scanner custom widget in SAP Analytics Cloud.
What component we need to have:
- SAPUI5 components: sap.m.Label, sap.m.Input, sap.m.Button, sap.ui.layout.form.SimpleForm.
- For barcode scanner, we will be using library from quaggaJS.
Custom Widget JSON
Let start with creating a custom widget JSON file, barcodescanner.json. In this file, I added the valid properties for Root object, Webcomponent object and Properties object. I am not using the Methods and Events object.
{
"id": "com.fd.djaja.sap.sac.scanner",
"version": "0.0.2",
"name": "barcodeScan",
"description": "Barcode Scanner",
"newInstancePrefix": "barcodeScan",
"icon": "data:image/png;base64,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",
"vendor": "Ferry Djaja",
"eula": "",
"license": "",
"imports": [ "input-controls" ],
"webcomponents": [
{
"kind": "main",
"tag": "com-fd-djaja-sap-sac-scanner",
"url": "http://localhost/SAC/sacbarcodescanner/barcodescanner.js",
"integrity": "",
"ignoreIntegrity": true
}
],
"properties": {
"metadata": {
"type": "string",
"description": "For internal use",
"default": ""
}
},
"methods": {
},
"events": {
}
}
Web Component JavaScript
We will implement the following Web Component JavaScript functions:
- constructor() – It is fired when the Web Component is initialized.
In this function, we create the shadow DOM root element, copy of the template element is added as a child element to the shadow DOM root element, create the unique ID (guid) for the HTML div and set the variable _firstConnection.constructor() { super(); _shadowRoot = this.attachShadow({ mode: "open" }); _shadowRoot.appendChild(tmpl.content.cloneNode(true)); this._id = createGuid(); _shadowRoot.querySelector("#export_div").id = this._id + "_export_div"; this._firstConnection = 0; }
- connectedCallback() – It is fired when the widget is added to the html DOM of the page.
In this function we check whether the app is in the edit mode or not and to list the available components (e.g,. Button, Text, Input Field, Panel, etc) in variable(this.metadata)["components"]
for future use.
connectedCallback() { try { if (window.commonApp) { let outlineContainer = commonApp.getShell().findElements(true, ele => ele.hasStyleClass && ele.hasStyleClass("sapAppBuildingOutline"))[0]; // sId: "__container0" if (outlineContainer && outlineContainer.getReactProps) { let parseReactState = state => { let components = {}; let globalState = state.globalState; let instances = globalState.instances; let app = instances.app["[{\"app\":\"MAIN_APPLICATION\"}]"]; let names = app.names; for (let key in names) { let name = names[key]; let obj = JSON.parse(key).pop(); let type = Object.keys(obj)[0]; let id = obj[type]; components[id] = { type: type, name: name }; } for (let componentId in components) { let component = components[componentId]; } let metadata = JSON.stringify({ components: components, vars: app.globalVars }); if (metadata != this.metadata) { this.metadata = metadata; this.dispatchEvent(new CustomEvent("propertiesChanged", { detail: { properties: { metadata: metadata } } })); } }; let subscribeReactStore = store => { this._subscription = store.subscribe({ effect: state => { parseReactState(state); return { result: 1 }; } }); }; let props = outlineContainer.getReactProps(); if (props) { subscribeReactStore(props.store); } else { let oldRenderReactComponent = outlineContainer.renderReactComponent; outlineContainer.renderReactComponent = e => { let props = outlineContainer.getReactProps(); subscribeReactStore(props.store); oldRenderReactComponent.call(outlineContainer, e); } } } } } catch (e) {} }
- disconnectedCallback() – It is fired when the widget is removed from the html DOM of the page (e.g. by hide).
In this function we reset the state of the “react store subscription”subscribeReactStore
that we defined inconnectedCallback()
.disconnectedCallback() { if (this._subscription) { // react store subscription this._subscription(); this._subscription = null; } }
- onCustomWidgetBeforeUpdate() – When the custom widget is updated, the Custom Widget SDK framework executes this function first.
In this function we set the status of _designMode()
as inchangedProperties
.
onCustomWidgetBeforeUpdate(changedProperties) { if ("designMode" in changedProperties) { this._designMode = changedProperties["designMode"]; } }
- onCustomWidgetAfterUpdate() – When the custom widget is updated, the Custom Widget SDK framework executes this function after the update.
In this function we will check if the widget instance loads for the first time. If yes then it will load the quaggaJS library and call the functionloadthis()
.
onCustomWidgetAfterUpdate(changedProperties) { var that = this; if (this._firstConnection === 0) { this._firstConnection = 1; let quaggaminjs = "http://localhost/SAC/sacbarcodescanner/quagga.min.js"; async function LoadLibs() { try { await loadScript(quaggaminjs, _shadowRoot); } catch (e) { alert(e); } finally { loadthis(that); } } LoadLibs(); } }
JavaScript Functions
- loadthis()
This function creates the div HTML element to place the UI elements: sap.m.Label, sap.m.Button and sap.m.Input. If is in design mode, the UI elements will be disabled.function loadthis(that) { var that_ = that; let buttonSlot = document.createElement('div'); buttonSlot.slot = "export_button"; that_.appendChild(buttonSlot); that_._Label = new sap.m.Label({ required: false, text: "Barcode value", design: "Bold" }); that_._exportButton = new sap.m.Button({ id: "scan", text: "Scan", icon: "sap-icon://bar-code", visible: true, tooltip: "Scan Barcode", press: function() { startScan(); } }); that_._Input = new sap.m.Input({ id: "scannedValue", type: sap.m.InputType.Text, placeholder: '' }); that_._simpleForm = new sap.ui.layout.form.SimpleForm({ labelSpanL: 3, labelSpanM: 3, emptySpanL: 3, emptySpanM: 3, columnsL: 1, columnsM: 1, editable: true, content: [ that_._Label, that_._Input, that_._exportButton ] }) that_._simpleForm.placeAt(buttonSlot); that_._renderExportButton(); if (that_._designMode) { sap.ui.getCore().byId("scan").setEnabled(false); sap.ui.getCore().byId("scannedValue").setEditable(false); } }
In design mode, the UI elements are disabled.
- _initQuagga()
Initialize the Quagga library with a given configuration and registers the methodonProcessed()
andonDetected()
.
function _initQuagga(oTarget, that) { var oDeferred = jQuery.Deferred(); // Initialise Quagga plugin - see https://serratus.github.io/quaggaJS/#configobject for details Quagga.init({ inputStream: { type: "LiveStream", target: oTarget, constraints: { width: { min: 640 }, height: { min: 480 }, facingMode: "environment" } }, locator: { patchSize: "medium", halfSample: true }, numOfWorkers: 2, frequency: 10, decoder: { readers: [{ format: "code_128_reader", config: {} }] }, locate: true }, function(error) { if (error) { oDeferred.reject(error); } else { oDeferred.resolve(); } }); if (!this._bQuaggaEventHandlersAttached) { // Attach event handlers... Quagga.onProcessed(function(result) { var drawingCtx = Quagga.canvas.ctx.overlay, drawingCanvas = Quagga.canvas.dom.overlay; if (result) { // The following will attempt to draw boxes around detected barcodes if (result.boxes) { drawingCtx.clearRect(0, 0, parseInt(drawingCanvas.getAttribute("width")), parseInt(drawingCanvas.getAttribute("height"))); result.boxes.filter(function(box) { return box !== result.box; }).forEach(function(box) { Quagga.ImageDebug.drawPath(box, { x: 0, y: 1 }, drawingCtx, { color: "green", lineWidth: 2 }); }); } if (result.box) { Quagga.ImageDebug.drawPath(result.box, { x: 0, y: 1 }, drawingCtx, { color: "#00F", lineWidth: 2 }); } if (result.codeResult && result.codeResult.code) { Quagga.ImageDebug.drawPath(result.line, { x: 'x', y: 'y' }, drawingCtx, { color: 'red', lineWidth: 3 }); } } }.bind(this)); Quagga.onDetected(function(result) { // Barcode has been detected, value will be in result.codeResult.code. If requierd, validations can be done // on result.codeResult.code to ensure the correct format/type of barcode value has been picked up // Set barcode value in input field sap.ui.getCore().byId("scannedValue").setValue(result.codeResult.code); // Close dialog that._oScanDialog.close(); }.bind(this)); // Set flag so that event handlers are only attached once... this._bQuaggaEventHandlersAttached = true; } return oDeferred.promise(); }
- startScan()
This function will be called once user presses the scan button. It creates the dialog box to scan the barcode and initiates the Quaggastart()
method. Thestart()
method starts the video stream and begins locating and decoding the images.
function startScan() { if (!this._oScanDialog) { this._oScanDialog = new sap.m.Dialog({ title: "Scan Barcode", contentWidth: "670px", contentHeight: "480px", horizontalScrolling: false, verticalScrolling: false, stretchOnPhone: true, content: [new sap.ui.core.HTML({ id: "scanContainer", content: "<div />" })], endButton: new sap.m.Button({ text: "Cancel", press: function(oEvent) { this._oScanDialog.close(); }.bind(this) }), afterOpen: function() { // TODO: Investigate why Quagga.init needs to be called every time...possibly because DOM // element is destroyed each time dialog is closed _initQuagga(sap.ui.getCore().byId("scanContainer").getDomRef(), this).done(function() { // Initialisation done, start Quagga Quagga.start(); }).fail(function(oError) { // Failed to initialise, show message and close dialog...this should not happen as we have // already checked for camera device ni /model/models.js and hidden the scan button if none detected MessageBox.error(oError.message.length ? oError.message : ("Failed to initialise Quagga with reason code " + oError.name), { onClose: function() { this._oScanDialog.close(); }.bind(this) }); }.bind(this)); }.bind(this), afterClose: function() { // Dialog closed, stop Quagga Quagga.stop(); } }); } this._oScanDialog.open(); }
- loadScript()
This function loads the external JavaScript library, in this case is quaggaJS.
function loadScript(src, shadowRoot) { return new Promise(function(resolve, reject) { let script = document.createElement('script'); script.src = src; script.onload = () => { console.log("Load: " + src); resolve(script); } script.onerror = () => reject(new Error(`Script load error for ${src}`)); shadowRoot.appendChild(script) }); }
- createGuid()
This function is to create the unique ID for HTML div element.
function createGuid() { return "xxxxxxxx-xxxx-4xxx-yxxx-xxxxxxxxxxxx".replace(/[xy]/g, c => { let r = Math.random() * 16 | 0, v = c === "x" ? r : (r & 0x3 | 0x8); return v.toString(16); }); }
Usage
Upload the Custom Widget
- Select Browse and Custom Widgets.
- Click + button to upload.
- Upload the barcodescanner.json.
- Widget is registered and ready to use.
Create and Insert the Widget in Analytics Application
- Select Create and Analytics Application.
- Insert the widget barcodeScan.
- You are ready to go.
References:
- Build a Custom Widget in SAP Analytics Cloud, Analytics Application
- Barcode scanning with device camera in SAPUI5 applications (without a native container)
- github.com/ferrygun/SACBarcodeScannerCustomWidget
- SAP Analytics Cloud Custom Widget Facebook Page
Thanks for the excellent blog. Have couple of clarifications, hope you can help me.
whereas the sap.ui.layout library is not loaded in app.html . Are you loading dynamically? What is the best way to handle dynamic library load?
Thanks for you time.
Regards
Raja
Hi,
As far as I understand, the UI5 components are loaded as part of the SAC bootstraps process. So you do not need to load them manually. It is dynamically loaded.
For my case is: https://sapui5.hana.ondemand.com/1.60.13/resources/
Regards,
Ferry
Hi Ferry
Sorry, one question. If I want to use UPC/ EAN-13, what a need to modify to read this type of barcode?
Regards!!!