DOM not rendering in TypeScript widget in 4.3 -> 4.8 upgrade

1086
2
Jump to solution
09-26-2018 09:54 PM
DirkVandervoort
Occasional Contributor II

We have a JSAPI v.4.3 application that we wanted to upgrade to 4.8. The application uses custom widgets that are built on TypeScript. I upgraded the TypeScript definitions when I changes the JSAPI version from 4.3 to 4.8.

The 4.3 JS application uses:

      var view = new MapView({

        map: webmap,

        container: "viewDiv"

      });

      view.then(function(e){

        // do something with e

      })

At 4.8, view.then() is replaced with view.when()

However, this affects the constructor of our custom widgets (in TypeScript tsx file). Specifically:

    render() {

        return (

            <div

                bind={this}

                class={CSS.base}>

                <!-- build a DOM here -->

            </div>

        );

    }

 

The application is failing with an error in Chrome:

Uncaught (in promise) TypeError: Cannot read property 'createElement' of undefined at Object.MyWidget.render (MyWidget.tsx:50)

Stepping through code in the debugger indicates that this exception occurs in the view.when(). The 'createElement' property indicates to me that an attempt is being made to create the DOM but that it cannot find itself. (?)

The application is failing with an error in Firefox and MS browsers that are not thrown to the console – instead an alert is displayed in the browser (FF) or Developer Tools (MS) with the following text:

Could not locate http://<URL>/<path>/MyWidget.tsx specified in http://<URL>/<path>/MyWidget.js.

I have verified that the tsx is correctly specified in the js file, even though the browser says otherwise.

I’m not sure how to reconcile these different exceptions, let alone resolve this issue. It is critical that we render the DOM, as it encapsulated our business logic. Does anyone have any thoughts on this issue? TIA

0 Kudos
1 Solution

Accepted Solutions
KellyHutchins
Esri Frequent Contributor

I ran a quick test using the custom widget sample from the api modifying it to add the bookmark widget to a view and it works using the sample. Can you reproduce it using the sample?

<!DOCTYPE html>
<html>

<head>
  <meta charset="utf-8">
  <meta name="viewport" content="initial-scale=1,maximum-scale=1,user-scalable=no">
  <link rel="stylesheet" href="https://js.arcgis.com/4.8/esri/css/main.css">
  <title>Create a custom widget - 4.8</title>

  <style>
    html,
    body,
    #viewDiv {
      padding: 0;
      margin: 0;
      height: 100%;
      width: 100%;
    }

    .esri-hello-world {
      background-color: #fff;
      color: #333;
      padding: 1em;
    }

  </style>
  <script>
    var locationPath = location.pathname.replace(/\/[^\/]+$/, "");
    window.dojoConfig = {
      packages: [{
        name: "app",
        location: locationPath + "/app"
      }]
    };

  </script>
  <script src="https://js.arcgis.com/4.8/"></script>
  <script>
    var widget;

    require([
      "esri/Map",
      "esri/views/MapView",
      "app/HelloWorld",
      "dojo/domReady!"
    ], function (
      Map,
      MapView,
      HelloWorld
    ) {
      var map = new Map({
        basemap: "streets"
      });

      var view = new MapView({
        container: "viewDiv",
        map: map,
        zoom: 4,
        center: [15, 65] // longitude, latitude
      });
      view.when(function () {
        var names = [{
              firstName: "John",
              lastName: "Smith"
            },
            {
              firstName: "Jackie",
              lastName: "Miller"
            },
            {
              firstName: "Anna",
              lastName: "Price"
            }
          ],
          nameIndex = 0;
        var widget = new HelloWorld({
          firstName: names[nameIndex].firstName,
          lastName: names[nameIndex].lastName,
          container: document.createElement("div")
        });
        view.ui.add(widget, "top-right");


        function changeName() {
          widget.set(names[++nameIndex % names.length]);
        }

        widget.on("greeted", function (event) {
          console.log(event);
        })
        setInterval(changeName, 1000);
      });


    });

  </script>
</head>

<body>
  <div id="viewDiv"></div>
</body>

</html>

View solution in original post

0 Kudos
2 Replies
KellyHutchins
Esri Frequent Contributor

I ran a quick test using the custom widget sample from the api modifying it to add the bookmark widget to a view and it works using the sample. Can you reproduce it using the sample?

<!DOCTYPE html>
<html>

<head>
  <meta charset="utf-8">
  <meta name="viewport" content="initial-scale=1,maximum-scale=1,user-scalable=no">
  <link rel="stylesheet" href="https://js.arcgis.com/4.8/esri/css/main.css">
  <title>Create a custom widget - 4.8</title>

  <style>
    html,
    body,
    #viewDiv {
      padding: 0;
      margin: 0;
      height: 100%;
      width: 100%;
    }

    .esri-hello-world {
      background-color: #fff;
      color: #333;
      padding: 1em;
    }

  </style>
  <script>
    var locationPath = location.pathname.replace(/\/[^\/]+$/, "");
    window.dojoConfig = {
      packages: [{
        name: "app",
        location: locationPath + "/app"
      }]
    };

  </script>
  <script src="https://js.arcgis.com/4.8/"></script>
  <script>
    var widget;

    require([
      "esri/Map",
      "esri/views/MapView",
      "app/HelloWorld",
      "dojo/domReady!"
    ], function (
      Map,
      MapView,
      HelloWorld
    ) {
      var map = new Map({
        basemap: "streets"
      });

      var view = new MapView({
        container: "viewDiv",
        map: map,
        zoom: 4,
        center: [15, 65] // longitude, latitude
      });
      view.when(function () {
        var names = [{
              firstName: "John",
              lastName: "Smith"
            },
            {
              firstName: "Jackie",
              lastName: "Miller"
            },
            {
              firstName: "Anna",
              lastName: "Price"
            }
          ],
          nameIndex = 0;
        var widget = new HelloWorld({
          firstName: names[nameIndex].firstName,
          lastName: names[nameIndex].lastName,
          container: document.createElement("div")
        });
        view.ui.add(widget, "top-right");


        function changeName() {
          widget.set(names[++nameIndex % names.length]);
        }

        widget.on("greeted", function (event) {
          console.log(event);
        })
        setInterval(changeName, 1000);
      });


    });

  </script>
</head>

<body>
  <div id="viewDiv"></div>
</body>

</html>
0 Kudos
DirkVandervoort
Occasional Contributor II

Thanks Kelly, your response didn't solve my problem, but it did focus my troubleshooting in a different and ultimately correct direction. The solution was to:

  1. Upgrade TypeScript to the latest version ( npm install -g typescript@latest)
  2. Upgrade the ArcGIS type definitions to the latest version (npm install --save @types/arcgis-js-api)
  3. Update tsconfig.json to include the line "jsxFactory": "tsx"

I now have a clean tsc and my widgets are correctly displaying in the DOM. Thanks again. Cheers!