How to Make Dynamic Web TWAIN Work with Polymer Shadow DOM
Tags: twain, document, javascript, polymer
Published: 2021-03-12 09:13:33

In the past, Dynamic Web TWAIN only supported HTML DOM elements.  Some web frameworks based on Shadow DOM, like Polymer, could not work with Dynamic Web TWAIN. Starting from version 16.1, Dynamic Web TWAIN was fully compatible with Shadow DOM. This article shares how to integrate Dynamic Web TWAIN SDK into a Polymer project for scanning documents in web browsers.

## Dynamic Web TWAIN Quick Start

1. [Download Dynamic Web TWAIN SDK](https://www.dynamsoft.com/web-twain/downloads).

2. Copy the **Dynamic Web TWAIN SDK <version>\Resources** folder to your project root directory.

3. Create an HTML file and get the full [sample code](https://github.com/Dynamsoft/Dynamic-Web-TWAIN) from GitHub:

```html
<!DOCTYPE html>
<html>
<head>
    <title>Hello World</title>
    <script type="text/javascript" src="Resources/dynamsoft.webtwain.initiate.js"></script>
    <script type="text/javascript" src="Resources/dynamsoft.webtwain.config.js"></script>
</head>
<body>
    <div id="dwtcontrolContainer" ></div>
    <input type="button" value="Scan" onclick="AcquireImage();" />
    <script type="text/javascript">
        Dynamsoft.WebTwainEnv.ProductKey = "LICENSE-KEY";
        function AcquireImage() {
          var DWObject = Dynamsoft.WebTwainEnv.GetWebTwain('dwtcontrolContainer');
          if (DWObject) {		
            DWObject.SelectSource(function () {		
              var OnAcquireImageSuccess = OnAcquireImageFailure = function () {
                  DWObject.CloseSource();
              };
              DWObject.OpenSource();
              DWObject.IfDisableSourceAfterAcquire = true;
              DWObject.AcquireImage(OnAcquireImageSuccess, OnAcquireImageFailure);
                      }, function () {
              console.log('SelectSource failed!');
                      });
          }
        }
    </script>
</body>
</html>
```

With such a few steps, a simple web document management app is done. Without a web server, we can instantly run the web document scanner app by double-clicking the HTML file.

![web document scan](https://dev-to-uploads.s3.amazonaws.com/uploads/articles/43qid17d3dkefo1rogwy.png)


A valid license key is required to make the app work. Get a [30-day FREE Trial License](https://www.dynamsoft.com/customer/license/trialLicense/?product=dwt) and update the code:

```js
Dynamsoft.WebTwainEnv.ProductKey = "LICENSE-KEY";
```

## A Polymer Project for Scanning Documents

Install the Polymer CLI:

```bash
npm i -g polymer-cli
```

After that, we can initialize the Polymer project with a template:

```bash
mkdir polymer-document-scan
cd polymer-document-scan
polymer init polymer-3-starter-kit
npm start
```

![polymer project](https://dev-to-uploads.s3.amazonaws.com/uploads/articles/hwz8xyrafyj8ic3idyty.png)
 

### Integrating Dynamic Web TWAIN into Polymer Project

Now, let's modify the default UI by adding a **Div** element and a **Button** element to the HTML template in **src/my-view.js:**

```js
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() {
    if (DWObject) {
      
    }
  }
}
```

![Add scan module to Polymer project](https://dev-to-uploads.s3.amazonaws.com/uploads/articles/ao0mz4ec6v489pdelbso.png)
 

It will fail to initialize Dynamic Web TWAIN object if we use the code of 'Hello World' sample:

```js
var DWObject = Dynamsoft.WebTwainEnv.GetWebTwain('dwtcontrolContainer');
```

The reason is the element cannot be found. To investigate the issue, open the developer console. 

![Shadow DOM](https://dev-to-uploads.s3.amazonaws.com/uploads/articles/ngqrahquwxjd6q69y1gr.png)
 

The developer console shows the Div element is a child of shadow DOM. Here is the JS code to get the Shadow DOM element:

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

Don't panic. The code could be simplified as follows:

```js
this.shadowRoot.querySelector('#dwtcontrolContainer');
```

Since Dynamic Web TWAIN has supported Shadow DOM, we can easily initialize Dynamic Web TWAIN object with a Shadow DOM element by using the `bind()` method:

```js
ready() {
    super.ready();
    // TODO: initialization
    this.initializeDWT();
  }

  initializeDWT() {
    // Dynamsoft.WebTwainEnv.ProductKey = "LICENSE-KEY";
    Dynamsoft.WebTwainEnv.CreateDWTObjectEx({ WebTwainId: 'Viewer' }, (obj) => {
      this.dwtObj = obj;
      obj.Viewer.bind(this.shadowRoot.querySelector('#dwtcontrolContainer'));
      obj.Viewer.width = 560;
      obj.Viewer.height = 600;
      obj.Viewer.show();

      var count = obj.SourceCount;
      for (var i = 0; i < count; i++) {
        this.shadowRoot.querySelector('#source').options.add(new Option(obj.GetSourceNameItems(i), i));
      }

    }, function (e) {
      console.log(e)
    });
  }
```

We create a click event for triggering document scanning.

```js
handleClick() {
    var obj = this.dwtObj;
    if (obj) {
      var onSuccess, onFailure;
      onSuccess = onFailure = function () {
        obj.CloseSource();
      };

      obj.SelectSourceByIndex(this.shadowRoot.querySelector('#source').selectedIndex); 
      obj.OpenSource();
      obj.IfDisableSourceAfterAcquire = true;	
      obj.AcquireImage(onSuccess, onFailure);
    }
  }
```


Finally, the web document scan app implemented in Polymer can work successfully.

![Polymer Shadow DOM document scan](https://dev-to-uploads.s3.amazonaws.com/uploads/articles/e5q9j0ttrtdhe6g73iey.png)
 

## Source Code

[https://github.com/yushulx/web-twain-document-scan](https://github.com/yushulx/web-twain-document-scan)