The issue of Dojo AMD failing to load a custom module

Trying to develop a web application using the ArcGIS API, Dojo, and Flask. The goal is to create a "file uploads" dialog by defining it as its own module with the Dojo 1.7 AMD convention (i.e. "define").

Current file structure:

\static
     home.js
     fileUpload.js
\templates
     home.html
main.py

The code for the dialog is copied from one of the Dojo Tutorials, consolidating all dialog-related functions into one module:

define([
    "dijit/registry",
    "dijit/Dialog",
    "dijit/form/Button",
    "dojo/ready",
    "dojo/domReady!"
], function (registry) {


    console.log("HELLO WORLD");


    return {
        // Show the dialog
        showDialog: function() {
            registry.byId("uploads").show();
        },

        // Hide the dialog
        hideDialog: function() {
            registry.byId("uploads").hide();
        }
    }

});

End of "home.js", attempts to create an instance of the dialog module:

var fu = new fileUpload();

In the "home.html" file, defines the dialog and uses the "fu" object's variables as event handlers for closing and opening the dialog:

<!DOCTYPE html>
<html>
<head>
    <meta charset="utf-8">
    <meta name="viewport" content="initial-scale=1, maximum-scale=1, user-scalable=no">

    <title>morPOP</title>

    <link rel="stylesheet" href="https://maxcdn.bootstrapcdn.com/bootstrap/4.0.0-beta/css/bootstrap.min.css" integrity="sha384-/Y6pD6FV/Vv2HJnA6t+vslU6fwYXjCFtcEpHbNJ0lyAFsXTsjBbfaDjzALeQsN6M" crossorigin="anonymous">
    <link rel="stylesheet" href="https://js.arcgis.com/4.5/esri/css/main.css">
    <link rel="stylesheet" href="../static/css/home.css">

    <script src="https://js.arcgis.com/4.5/"></script>

    <script src="../static/js/home.js"></script>
</head>

<body>
    <!-- Map -->
    <div id="viewDiv"></div>

    <!-- Upload Button -->
    <div class="btn-toolbar" role="toolbar" aria-label="Toolbar with button groups">
        <button type="button" id="uploadbtn" class="btn btn-primary" onclick="fu.showDialog()">Upload</button>
    </div>

    <!-- Upload Dialog -->
    <div class ="dijitHidden">
        <div id="uploads" data-dojo-type="dijit/Dialog" data-dojo-props="title:'Upload Files'">
            <p>The following files must be uploaded to run a simulation. File names must match those listed below.</p>
            <p>Acceptable file extensions: .txt or .csv</p>
            <ul>
                <li>Geographic data</li>
                <ul>
                    <li>Age_Dissemination</li>
                </ul>
                <li> Probability Data </li>
                <ul>
                    <li>ageContactDuration_hospital_nurse</li>
                    <li>ageContactDuration_hospitalPatient</li>
                    <li>ageContactNumber_hospital</li>
                </ul>
                <li> ??? </li>
                <ul>
                    <li>Census_Division_Mapping</li>
                </ul>
            </ul>

            <button onclick="fu.hideDialog();">Finish</button>
        </div>
    </div>

</body>

</html>

Error message from Google Chrome developer console:

Uncaught TypeError: Cannot read property 'on' of undefined
    at new g (init.js:56)
    at home.js:51
    at Q (init.js:18)
    at init.js:18
    at A (init.js:18)
    at ea (init.js:18)
    at d (init.js:20)
    at HTMLScriptElement.<anonymous> (init.js:23)

Unclear what property "on" triggers this error. Any insights on why declaring an instance of my module is unsuccessful?

** EDIT ***

Updated home.js file now "require"s fileUpload.js, but clicking the "submit" button results in another error:

(index):24 Uncaught ReferenceError: fu is not defined
  at HTMLButtonElement.onclick ((index):24)

Visit this link for updated home.js file on Plunkr.

Answer №1

When working with AMD, dependencies are managed by defining them using the define() function. However, modules must be imported using the require() function by the client of the module. You can refer to the documentation here. It's important to note that attempting to instantiate a required module using new is not the correct approach.

If you want to use a module in a DOM event handler, you need an additional wrapper. For example, your HTML would include onclick="whenClicked()" if the function is within scope:

function whenClicked() {
  require(['fileUpload'], function(fu) {
    fu.showDialog();
  });
}

Assuming that 'fileUpload' is correctly specified as an AMD module.

EDIT: A modified version of the OP's sample on Plunker can be found here: https://plnkr.co/edit/QFckwndDicGpTfzhGwFC?p=preview

The module definition for `fileUpload.js` has been changed so that a basic alert is displayed:

define([
"dijit/registry",
"dijit/Dialog",
"dijit/form/Button",
"dojo/domReady!"
], function (registry) {
  return {
    // Show the dialog
    showDialog: function() {
        //registry.byId("uploads").show();
        alert("this is file upload mock");
    }
  }
});

The `home.js` file hosts the definition of `whenClicked`:

function whenClicked() {
  require({
    packages: [
      {name: "fileUpload", 
      // location should point to fileUpload.js on your target server
      location: "https://run.plnkr.co/uv2ILkhQpQC2wqRV",
      main: "fileUpload"}
    ]},
    ['fileUpload'], function(fu) {
      console.log("fileupload");
      fu.showDialog();
  });
}

Note that specifying the `location` of the module is similar to what bRIMOs mentioned in another answer. However, my approach configures the location only for this specific code wrapped by require, whereas bRIMOs' approach is global.

Keep in mind that Plunker rebuilds the `location` URL each time you reload the editor, which means you may need to fix the location prefix every time you reload the page for it to work properly.

Answer №2

Perhaps you overlooked configuring the path in the dojo config to access the fileupload.js file via the AMD loader. The dojoConfig documentation provides various configuration options (such as baseURL, package, paths, etc.). Below is an example of how to configure using packages, allowing Dojo to load your files seamlessly with require.

Before loading your ArcGIS JS API

<script src="url_api_js"></script>
, make sure to follow these steps (configuring Dojo with dojoConfig variable).

<script type="text/javascript">
   var dojoConfig = {
       packages: [
           { 
                name: "mypackage", 
                location: location.pathname.replace(/[^\/]+$/, '') +"/static"
           }
       ]
   };
<script>
<script src="url_api_js"></script>

Then within your code, use the package name/file name as shown below:

require(['mypackage/fileUpload'], function(upload) {
    upload.showDialog();
});

Note: the location may vary depending on the server type. In this example, the location is similar to:

{location_name}/static/fileupload.js

I hope this explanation proves helpful.

Similar questions

If you have not found the answer to your question or you are interested in this topic, then look at other similar questions below or use the search

"Seeking assistance with concept sharing and content transmission. In need of guidance

Basic Question I'm stuck trying to brainstorm a concept to reach my objective. I am having trouble figuring out how to navigate the DOM correctly with my chosen method. The Objective First, let me explain what I am doing: I use ajax to bring HTML ...

Firebase Issue in Next JS Authentication Flow: Unconfirmed Email Causes "auth/email-already-in-use" Error to Trigger

I have encountered a perplexing issue while setting up user registration with Firebase Authentication in my Next.js application. The problem arises when I try to register a new user with an unverified email address. Instead of following the correct flow to ...

Creating an axios URL using Vue data results in receiving the value of undefined

I'm currently experimenting with axios to retrieve data from openweathermap. I've been working on constructing the URL by utilizing various methods to extract latitude and longitude from the user's browser, followed by a function call to pie ...

Transferring data between two distinct programs linked to a single router without internet connection using JavaScript and Electron

I am currently working on implementing a feature called 'add monitors' into my program. This feature would allow users to display data on another computer (a sub-program) within the same building, without the need for internet connectivity. The t ...

What is the best way to use Python and Selenium to click on an angularjs link by comparing it to the text entered by the user?

A user can input a specific link that they would like to click. For example, if the user inputs "Tampa Bay Downs" for the variable track. In my Python Selenium test program, I will search for the following code: <a ng-click="updateFavorite()(raceInfo. ...

Execute an asynchronous request using Javascript to communicate with a Spring Controller

I've created a JSP page that includes some JavaScript code: function sendData(tableID) { var table = document.getElementById(tableID); var dataArray= new Array(); for (var i = 1;i<table.rows.length; i++){ var row = table. ...

JavaScript Object-Oriented Programming - Accessor method that retrieves a property from the parent

Having trouble with implementing getters and setters for model objects in Angular. Facing an error: TypeError: Cannot read property 'firstName' of undefined at User.firstName (http://run.plnkr.co/AvdF2lngjKB76oUe/app.js:35:32) The code snippet: ...

Switch between active tabs (Typescript)

I am working with an array of tabs and here is the code snippet: const navTabs: ITab[] = [ { Name: allTab, Icon: 'gs-all', Selected: true }, { Name: sources.corporateResources, Icon: 'gs-resources', Selected: false }, { Name ...

JavaScript combined with a dynamic menu, a customized current link style using CSS, and a site built on PHP

Here's my current website setup: My website is modular and uses dynamic inclusion. The header is a crucial part of the main page, which is responsible for displaying content from specific links on the site. External links to CSS and js files are incl ...

Exploring the intricacies of JSON object retrieval

I'm currently working on a form that allows users to submit address details for a selected location. However, before submitting the form, I want to give the user the ability to preview the address that will be sent. The addresses are stored within a J ...

To retrieve a CSV file on the frontend, simply click a button in an AngularJS application that communicates with NodeJS and ExpressJS

How can I download a .csv file from the frontend? This is the code I am currently using: $http.get('/entity/consultations/_/registerationReport' ) .success(function (data) { myWindow = window.open('../entity/consultations/_/r ...

Tips for displaying a Rails action without a layout in html format using Ajax

Is it possible to render the new action without the application layout and without altering the current code structure? class FoobarController < ApplicationController def new @foobar = Foobar.new end # ... end When a user clicks on = link_ ...

Within jQuery lies the power to perform multiplication operations effortlessly

I'd like to accomplish this using jQuery: var menuItems = document.getElementsByTagName("li"); for (var k = 0; k < menuItems.length; k++) { if (menuItems[k].className == "menu") { var child = menuItems[k].firstChild; if ...

What is the method for ensuring text remains within a square while it is being relocated?

Check out this jsfiddle where you can interact with a moving square: http://jsfiddle.net/helpme128/3kwwo53t/2/ <div ng-app="test" ng-controller="testCtrl"> <div id="container"> <div class="shape" ng-draggable='dragOptions& ...

Modifying canvas border colors using AngularJS

Currently, I am in the process of learning AngularJS and have developed a website that includes a canvas element. My main objective is to change the border color after clicking on a checkbox. Here is the code snippet for canvas.html : <!DOCTYPE html&g ...

Special character Unicode regex for names

After spending the entire day reading about regex, I am still struggling to fully grasp it. My goal is to validate a name, but the regex functions I have found online only include [a-zA-Z], omitting characters that I need to allow. Essentially, I require ...

Should the article ID be sent to the ajax file, or should the ajax file retrieve the article ID directly? This dilemma arises in a

I am trying to pass the current article ID to an ajax file. The URL of the ajax file is something like www.web.com/plugins/system/ajax.php, so using JRequest::getInt(id) always returns 0 integer. However, in a non-ajax file, I can get the ID the same way. ...

Tips on expanding the space between words in a scrolling "marquee" text

Looking for some assistance with my jQuery project involving a horizontal scrolling "marquee" text. I am currently trying to adjust the size of the gap between the phrases in the marquee. Here is an example with the phrase "HEY THERE". jQuery(document ...

Dynamic Node.js server constantly updating

My goal is to create a dynamic Node.js Express server that updates live, possibly by creating a specific route like /update to load a new configuration file. My concern is that the server could be in any state when the update occurs. It's possible tha ...

Incorporating a function from a separate .js file into an index.ejs view using app.js

graphs.js: contains a function that initiates an API call and retrieves an object containing an HTML link for embedding a graph. app.js: includes the following (graphs.js has been imported): var express = require("express"); var app = express(); var grap ...