Why Polymer Can’t Work with Dynamic Web TWAIN

I’ve noticed some developers are confused about how to use Dynamic Web TWAIN (DWT) SDK in Polymer (an open-source JavaScript library for building web applications) projects. The answer is “No, you can’t” so far. In this article, I will show why it will fail to use Dynamic Web TWAIN with Polymer.

Starting Up A Polymer Project

Install the Polymer CLI:

npm i -g polymer-cli

Initialize the Polymer project from the template:

mkdir polymer-scan
cd polymer-scan
polymer init polymer-3-starter-kit
npm start
polymer init project

Integrating Dynamic Web TWAIN into Polymer Project

DWT ‘hello world’ sample

Let’s take a glimpse of the code snippet of scanning documents with Dynamic Web TWAIN APIs:

<!DOCTYPE html>
<html>
<head>
    <title>Dynamic Web TWAIN</title>
    <script src="https://unpkg.com/dwt@15.2.0/dist/dynamsoft.webtwain.min.js"></script> 
</head>
<body>
    <input type="button" value="Scan" onclick="AcquireImage();" />
    <div id="dwtcontrolContainer"></div>
 
    <script type="text/javascript">
        var DWObject;
        Dynamsoft.WebTwainEnv.ProductKey = 'LICENSE-KEY';
        Dynamsoft.WebTwainEnv.AutoLoad = true;
        Dynamsoft.WebTwainEnv.RegisterEvent('OnWebTwainReady', Dynamsoft_OnReady);
        function Dynamsoft_OnReady() {
            DWObject = Dynamsoft.WebTwainEnv.GetWebTwain('dwtcontrolContainer');
        }
        function AcquireImage() {
            if (DWObject) {
                DWObject.SelectSource(function () {
                    var OnAcquireImageSuccess, OnAcquireImageFailure;
                    OnAcquireImageSuccess = OnAcquireImageFailure = function () {
                        DWObject.CloseSource();
                    };
                    DWObject.OpenSource();
                    DWObject.IfDisableSourceAfterAcquire = true;
                    DWObject.AcquireImage(OnAcquireImageSuccess, OnAcquireImageFailure);
                }, function () {
                    console.log('SelectSource failed!');
                });
            }
        }
    </script> 
</body>
</html>

Here’s the screenshot:

web document scan

According to the developer’s guide, Dynamic Web TWAIN will globally search HTML document for <div id=”dwtcontrolContainer”></div> element and render it as an image viewer. Once the initialization is done, we can see the borders of the image viewer.

Empower Polymer project with document scanning API

The next step is to transplant the code to the Polymer project.

Open index.html to add Dynamic Web TWAIN JS URL and set relevant properties:

<my-app></my-app>
  <script src="https://unpkg.com/dwt@15.2.0/dist/dynamsoft.webtwain.min.js"></script>
  <script type="text/javascript">
    var DWObject;
    Dynamsoft.WebTwainEnv.ProductKey = 'LICENSE-KEY';
    Dynamsoft.WebTwainEnv.AutoLoad = true;
    Dynamsoft.WebTwainEnv.RegisterEvent('OnWebTwainReady', Dynamsoft_OnReady);
  </script>

In src/my-view.js, add a <div> and a <button> elements:

class MyView1 extends PolymerElement {
  static get template() {
    return html`
      <style include="shared-styles">
        :host {
          display: block;

          padding: 10px;
        }
      </style>

      <div class="card">
      <div id="dwtcontrolContainer"></div>
      <button on-click="handleClick">scan</button>
      </div>
    `;
  }

  handleClick() {
    var DWObject = Dynamsoft.WebTwainEnv.GetWebTwain('dwtcontrolContainer');
    if (DWObject) {
      DWObject.SelectSource(function () {
          var OnAcquireImageSuccess, OnAcquireImageFailure;
          OnAcquireImageSuccess = OnAcquireImageFailure = function () {
              DWObject.CloseSource();
          };
          DWObject.OpenSource();
          DWObject.IfDisableSourceAfterAcquire = true;
          DWObject.AcquireImage(OnAcquireImageSuccess, OnAcquireImageFailure);
      }, function () {
          console.log('SelectSource failed!');
      });
  }
  }
}

Refresh the homepage:

polymer document scan

You can now see the scan button, but there’s no image viewer comparing to the basic DWT sample.

Debugging Polymer code for DWT null exception

Press F12 to open Chrome developer tools. Click the scan button to debug the JavaScript code.

polymer debug

As you can see above, the value of DWObject is null. Probably it failed to find the dwtcontrolContainer. We can verify the issue with the following code:

var element = document.getElementById('dwtcontrolContainer')

The value of element is null too. The <div> element is out there, why we cannot get it? Right-click on the UI element to take a further inspect.

shadow dom

See the shadow root? The shadow root is the start of a new shadow DOM. We cannot use the getElementById() function to get the element encapsulated by shadow DOM. Chrome allows us to copy the JS path.

dom js path

The JavaScript code of getting the <div> element is as follows:

document.querySelector("body > my-app").shadowRoot.querySelector("app-drawer-layout > app-header-layout > iron-pages > my-view1").shadowRoot.querySelector("#dwtcontrolContainer")

Polymer uses shadow DOM to build web component, which is currently inaccessible to Dynamic Web TWAIN. The issue can be solved if Dynamic Web TWAIN can support initializing the dwt control container with an HTML element object rather than an ID.