Dojo AMD not loading custom module - javascript

I'm trying to make a web application using the ArcGIS API, Dojo, and Flask. I want to start by making a "file uploads" dialog, which I am trying to define as its own module using the Dojo 1.7 AMD convention (i.e. "define").
Here is my file structure:
\static
home.js
fileUpload.js
\templates
home.html
main.py
Here is the code for the dialog (copied from one of the Dojo Tutorials). I am basically trying to put all dialog related function (i.e. show and hide) in 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();
}
}
});
At the end of "home.js" I try to create and instance of the dialog module:
var fu = new fileUpload();
Then in my "home.html" file, I define the actual dialog and try to use 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>
The error that I get in the google Chrome developer console is the following:
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)
I'm not sure what "on" property the error is referring to. Does anyone have any ideas? Why can't I declare an instance of my module?
** EDIT ***
I've changed my home.js file to "require" fileUpload.js, but I am now getting the following error when I try to click the "submit" button:
(index):24 Uncaught ReferenceError: fu is not defined
at HTMLButtonElement.onclick ((index):24)
Please see the following plunkr for my updated home.js file: https://plnkr.co/edit/9dFVHsFOCji1aE0ZeLRQ?p=preview

When using AMD you manage your dependencies by defining things as you have done with define() but client of module must import it using require() function, see docs, meanwhile you try to instantiate required module via new which is not correct.
To use some module in DOM handler you need extra wrapper e.g. your HTML would make onclick="whenClicked()" if you have this function in scope:
function whenClicked() {
require(['fileUpload'], function(fu) {
fu.showDialog();
});
}
assuming of course that 'fileUpload' is correctly specified AMD module.
EDIT: modified version of OP sample on Plunker:
https://plnkr.co/edit/QFckwndDicGpTfzhGwFC?p=preview
Note fileUpload.js module definition changed so that 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");
}
}
});
as well as home.js hosting 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 showing location of module is similar to what bRIMOs said in other answer. My approach configures however location only for this particular code wrapped by require; approach of bRIMOs is global.
Be aware however that Plunker is rebuilding location URL each time you reload editor :/ it effectively means tha you fix location prefix, run it fine, reload Plunker page, and it is broken again.

I think you missed to configure the path in dojo config in order to access the fileupload.js file by the AMD loader , In the dojoConfig doc there is many type of config ( basURl ,package , paths ...) , below you can see how to make configuration using packges , and dojo will load you files using require without any problem
So before loading your arcgis js api <script src="url_api_js"></script> be sur to do the folowing (configuring dojo with dojoConfig var)
<script type="text/javascript">
var dojoConfig = {
packages: [
{
name: "mypackage",
location: location.pathname.replace(/[^\/]+$/, '') +"/static"
}
]
};
<script>
<script src="url_api_js"></script>
and the inside your code use the name of package/name of file as below
require(['mypackage/fileUpload'], function(upload) {
upload.showDialog();
});
NB: the location could change , according to the server type , in this exemple the location is like : {location_name}/static/fileupload.js
hopefully this would help you .

Related

Issue loading the backbone view for the first time

I want to load one of my javascript automatically on the load of my html page.
The html page on load of which I want to load my js file.
<!DOCTYPE html>
<html>
<head>
<script src="/static/js/LoginApp.js"></script>
<meta charset="ISO-8859-1">
<title>Insert title here</title>
</head>
<body>
<div class="container">
<h1>Backbone Tutorial Blogroll App</h1>
<button type="button" id="newButton">Click Me!</button>
<script src="/static/js/require.js"></script>
<script src="/static/js/LoadView.js"></script>
</div>
</body>
</html>
The javascript I want to load is
LoadView.js
define([
'jquery',
'underscore',
'backbone',
'LoadView',
'text!NewViewCheck.html',
], function($, _, Backbone, LoadView, NewViewCheck) {
var Task = Backbone.Model.extend({
defaults: {}
});
TheView = Backbone.View.extend({
model: new Task(),
events: {
'click #newButton': 'initializeView',
},
//'template' provides access to instance data when rendering the view
template: _.template(NewViewCheck),
initialize: function() {
console.log('Inside the initialize function');
this.render();
},
render: function() {
//this.$el.html(this.template());
console.log(labelsLocale);
this.$el.html(this.template({}));
$('#dialogContent').empty().append(this.$el);
$('#addUserDefinedOption').modal('show');
},
initializeView: function() {
var theView = new TheView();
console.log('abc');
},
});
$(document).ready(function() {
//console.log('abc');
})
});
I am getting the following error
Uncaught Error: Mismatched anonymous define() module
Please help me thanks in advance.
The error is because you have:
<script src="/static/js/LoadView.js"></script>
The docs says:
If you manually code a script tag in HTML to load a script with an anonymous define() call, this error can occur.
And that's what you're doing.
And in solutions:
Be sure to load all scripts that call define() via the RequireJS API. Do not manually code script tags in HTML to load scripts that have define() calls in them.
If you manually code an HTML script tag, be sure it only includes named modules, and that an anonymous module that will have the same name as one of the modules in that file is not loaded.
So simply load it using requireJS from your main file or name the module

How do I include jQuery code in my node.js web app?

so I've been working on a (fairly simple) RESTful app using node.js, and I've made it towards the very last bit, now the only bit missing is using jQuery to manipulate the html page so I can edit the content of the html - and it's driving me absolutely mad.
I took the try.jquery.com tutorial, and it was pretty smooth; I'd by no means call myself a master of jquery, but I have very little trouble writing the code for basic html manipulation, except I never really considered where the jquery code would go. I've tried a bunch of different stuff and only one (really inconvenient) way has worked, so I was wondering if I could get some clarification.
(Note: all the js files are in the root folder, and index.html is in root/public; and I'm basically just running app.js through npm/package.json)
I've tried including the jQuery code in the main app.js file:
app.js
//some imports/requires here
var $ = require('jquery');
//more imports/requires here
//error; document is undefined
$(document).ready($('h1').text('Im Here');
app.get('/', function (req, res) {
res.sendFile(__dirname+'/public/index.html');
});
index.html
<script src="https://ajax.googleapis.com/ajax/libs/jquery/1.6.1/jquery.min.js"></script>
<title>Inspiratorator</title>
<link rel="stylesheet" type="text/css" href="css/style.css">
<script="../app.js"></script>
I've tried including the jQuery code in its own file (tried just letting the code sit in the js file, and tried exporting the code as a function and calling it from app.js - both did nothing):
jusQueryin.js
var $ = require('jQuery'); //tried with and without this
$(document).ready(function () {
$(' button ').on( 'click', $('h1').text("I'm here") );
console.log('kpa');
});
index.html
<script src="https://ajax.googleapis.com/ajax/libs/jquery/1.6.1/jquery.min.js"></script>
<title>Inspiratorator</title>
<link rel="stylesheet" type="text/css" href="css/style.css">
<script="../jusQueryin.js"></script>
I've also tried (this worked, but I don't know how I would deal with the code in here from other .js file, if it is possible):
index.html
<script src="https://ajax.googleapis.com/ajax/libs/jquery/1.6.1/jquery.min.js"></script>
<title>Inspiratorator</title>
<link rel="stylesheet" type="text/css" href="css/style.css">
<script>
$(document).ready(function () {
$(' button ').on( 'click', $('h1').text("I'm here") );
console.log('kpa');
});
</script>
I've also tried different variations(i.e. including the 2nd part of the ready function in a function (or not), using an onClick event inside the dom.ready function, etc..), but the only one that worked was the last approach
Ideally, I'd like to be able to use the jQuery code inside app.js, less ideally would be in its own file; or if I have to include it inside the html file for some reason, I would at least need to be able to communicate with the code in the script block so that I can give it info from the database and so on.
Remeber one thing jQuery needs a window object to work. The first functionality of jquery is as dom query, dom is within a window object. As a result you must load the jquery and attach it to a window object.
As a node app you will have a browser window as a view to your app. Try adding jquery to that window from a CDN, add your requires there, voila the containing scope(window) which contains jquery now as global passes it also to the newly required file.
Error: jQuery requires a window with a document
index.html
<script>
window.$ = window.jQuery = require('./node_modules/jquery');
</script>
<script>
var UI = require('./controllers/UI');
UI.init(window);
</script>
Now var UI, which is a module in my case, contains

Durandal JS and Google Plus Sign in Javascript API

So I'm trying to build a mobile app using Durandal. However, I am having trouble to do so with Google plus JS API integration. I think here is the problem: The javascript client for gapi comes with asynchronous loading, so durandal initialization will crash having gapi undefined and because of this, the css components also do not render properly also. I have tried putting the following script tags in the login.html file of my view for login.js or even in the require.js section of my main.js but it's still not working. Scripts for linking to Google Api:
<script src="https://apis.google.com/js/client:platform.js" async defer> </script>
<script src="https://apis.google.com/js/platform.js?onload=onLoadCallback" async defer></script>
//onSignInCallBack function to call in login.js after user signs in vis Google Plus
onSignInCallback: function(authResult) {
gapi.client.load('plus','v1').then(function() {
if (authResult['access_token']) {
$('#authOps').show('slow');
$('#gConnect').hide();
var user_access_token = authResult['access_token'];
var id_token = authResult['id_token'];
} else if (authResult['error']) {
// There was an error, which means the user is not signed in.
console.log('There was an error: ' + authResult['error']);
$('#authOps').hide('slow');
$('#gConnect').show();
}
console.log('authResult', authResult);
});
},
Here is my main.js file:
requirejs.config({
paths: {
'text': '../Scripts/text',
'durandal': '../Scripts/durandal',
'plugins': '../Scripts/durandal/plugins',
'transitions': '../Scripts/durandal/transitions',
'knockout' : '../Scripts/knockout-3.1.0',
'bootstrap': '../Scripts/bootstrap',
'jquery':'../Scripts/jquery-1.9.1',
'async':'../Scripts/async'
}
});
define(['durandal/system',
'durandal/app',
'durandal/viewLocator',
'durandal/binder',
'utils/routines',
'async!https://apis.google.com/js/platform.js?onload=onLoadCallback',
'async!https://apis.google.com/js/client:platform.js'
], function (system, app, viewLocator, binder,routines,callback,gapi) {
//>>excludeStart("build", true);
system.debug(true);
//>>excludeEnd("build");
app.configurePlugins({
router: true,
dialog: true,
widget: true
});
app.start().then(function() {
//Replace 'viewmodels' in the moduleId with 'views' to locate the view.
//Look for partial views in a 'views' folder in the root.
viewLocator.useConvention();
//Show the app by setting the root view model for our application with a transition.
app.setRoot('shell/shell', 'entrance');
// override bad route behavior to write to
// console log and show error toast
/*
router.handleInvalidRoute = function (route, params) {
logger.logError('No route found', route, 'main', true);
};
*/
});
});
Here is my index.html:
<!DOCTYPE html>
<html>
<head>
<meta charset="utf-8" />
<meta http-equiv="X-UA-Compatible" content="IE=edge, chrome=1" />
<meta name="apple-mobile-web-app-capable" content="yes" />
<meta name="apple-mobile-web-app-status-bar-style" content="black" />
<meta name="format-detection" content="telephone=no" />
<meta name="viewport" content="width=device-width, initial-scale=1.0" />
<link rel="apple-touch-startup-image" href="/Content/images/ios-startup-image- landscape.png" media="(orientation:landscape)" />
<link rel="apple-touch-startup-image" href="/Content/images/ios-startup-image-portrait.png" media="(orientation:portrait)" />
<link rel="apple-touch-icon" href="~/Content/images/icon.png" />
<link href="/Content/ie10mobile.css" rel="stylesheet" />
<link href="/Content/bootstrap.min.css" rel="stylesheet" />
<link href="/Content/font-awesome.min.css" rel="stylesheet" />
<link href="/Content/durandal.css" rel="stylesheet" />
<link href="/Content/starterkit.css" rel="stylesheet" />
<script type="text/javascript">
if (navigator.userAgent.match(/IEMobile\/10\.0/)) {
var msViewportStyle = document.createElement("style");
var mq = "##-ms-viewport{width:auto!important}";
msViewportStyle.appendChild(document.createTextNode(mq));
document.getElementsByTagName("head")[0].appendChild(msViewportStyle);
}
</script>
</head>
<body>
<div id="applicationHost">
<div class="text-center">
<br/><br/><br/><br/>
<i class="fa fa-spinner fa-spin"></i>
<div class="message">
Loading....
</div>
</div>
</div>
<script type="text/javascript" src="Scripts/require.js" data-main="/App/main"></script>
</body>
</html>
Have anyone ever tried to integrate google plus sign in with Durandal and have this same issue? Help and suggestion is much appreciated!!
For remote async loads under Durandal (or, in other words, under RequireJS), you'll need the async, goog, and propertyParser plugins. See the readme at that link.
As an example, here's what we do for Google Maps:
in the paths property of RequireJS (usually in the main.js file of Durandal), the following order:
'async': '../Scripts/plugins/async',
'propertyParser': '../Scripts/plugins/propertyParser',
'goog': '../Scripts/plugins/goog'
the define, also in the main.js file of Durandal, just before the main function that kicks off the application:
define('jquery', function() { return jQuery; });
define('knockout', ko);
define('gmaps', ['async!http://maps.google.com/maps/api/js?sensor=false'],
function () {
return window.google.maps;
});
define(['durandal/system',
'durandal/app',
'durandal/viewLocator',
'bindings',
'extenders',
'validations'],
function (system, app, viewLocator, bindings, extenders, validations) {
Notice the async! before the remote API URL. Also notice that we don't actually define gmaps for the main entry point of the application. We set up a global define before the main entry point.
Please let me know if that helps.
So I found the solution to integrate the google plus sign in into my Durandal app. You basically need to include asyncJS (don't have to include googJS/propertyParserJS, goog only works for very specific google APIs - (https://developers.google.com/loader/?csw=1#AvailableAPIs) in the require section of main.js and define the google client api in main.js. However, you cannot use the following urls to call the api in your define in main.js.
<script src="https://apis.google.com/js/client:platform.js" async defer> </script>
<script src="https://apis.google.com/js/platform.js?onload=onLoadCallback" async defer></script>
In the Google Plus Sign In Javascript API documentation, you are asked to include the above script tags in your html file. However, this does not work with requireJS and Async. Instead you need to call Google Client API and use the following url in main.js:
define('gapi',['async!https://apis.google.com/js/client.js!onload'], function() {
console.log('gapi loaded: ' + gapi);
return window.gapi;
});
You can then call gapi in your specific viewmodel after doing this by including it in the define section of your viewmodel. To implement the google plus sign in, you can then call the following function after defining and passing in the parameters as specified by the instructions in Google Plus Sign in Javascript API (https://developers.google.com/+/web/signin/javascript-flow):
define(['gapi'], function(gapi) {
return {
additionalParams : {
'callback': "specify a callback function here",
'clientid' :"your client_ID",
'scope' : "scope for permissions",
'cookiepolicy' : "single_host_origin"
},
googlelogin: function() {
gapi.auth.signIn(this.additionalParams);
}
}
});
I then bind the googlelogin method to my google sign in button using
data-bind="click:googlelogin". This will let you sign in using your google plus after clicking the button. However, this method seems to have a problem when it comes to the callback for me. So here is the second alternative which works for me, use the following method to authorize the user and execute the callback (you must define this)when your sign in button is clicked:
gapi.auth.authorize(parameters,signinCallBack);
The parameters are specified here: (https://developers.google.com/api-client-library/javascript/reference/referencedocs#gapiauthauthorize). Hope this helps you integrate your Durandal/RequireJS app with Google Plus and Ouath2 for client side JS implementation! Thank you #EricTaylor for guiding me!

RequireJS, jquery still undefined

I know this has already been discussed, but after searching for a while I can't figure out why my small setup does not load jquery correctly with requireJS.
I'm running a small sample html page from 'file://' and try to load 2 modules with a call to require:
jquery
a custom module I wrote
If my custom module loads correctly (i can use it with its alias in the require call, jquery is always undefined)
I tried to setup paths in require.config, as well as shim (exporting '$' or 'jQuery') but it does not work.
The only way i can get jquery to correctly load, is removing all paths definition and naming the jquery file on my filesystem 'jquery.js'
Here is my config:
main.js:
require.config({
baseUrl: 'scripts',
paths: {
jquery: 'jquery-2.1.3.min' //does not work
//jquery: 'http://code.jquery.com/jquery-2.1.3.min.js' //does not work either
}
});
console.log( "main.js is loaded" ); //this is correctly ouputed to the console
test.html:
<!DOCTYPE html>
<html>
<head>
</head>
<body>
<!--
... page content ...
-->
<!-- main.js is loaded from data-main -->
<script data-main="scripts/main" src="scripts/require.js"></script>
<script type='text/javascript'>
require(
['jquery','custom'],
function($, Custom){
console.info('$:');
console.info($); //outputs undefined
console.info('Custom:');
console.info(Custom); //outputs my custom object
});
</script>
</body>
</html>
Once again, it works if I remove all paths definition for jquery, and simply name my jquery js file 'jquery.js' but this is sloppy.
Can somebody points me on the right way to go ?
The problem is that you load your RequireJS configuration, which is in main, through data-main. The data-main attribute merely tells RequireJS to load the module listed there but the loading is still asynchronous, so main may load after RequireJS tries to load jQuery. When this happens, RequireJS fails to find jQuery and $ is undefined. (Incidentally, I'd suggest setting enforceDefine to true in your RequireJS configuration so that you get an error message telling you when a module has not loaded. That's a better clue than having an undefined symbol.)
One solution would be to move your configuration outside of main. So you remove it from main and add it to a script element in front of the one loading RequireJS:
<script>
// RequireJS will use the value of `require` as its configuration.
require = {
baseUrl: 'scripts',
paths: {
jquery: 'jquery-2.1.3.min'
},
enforceDefine: true
};
</script>
<script src="scripts/require.js"></script>
Or you can nest require calls to force main to load before any other module:
require(['main'], function () {
require(['jquery','custom'], ...
});

Adding dojo widget inside custom widget

I am making a small dojo widget, basically extending the dailog widget and want to add simple widgets like a text input a few labels etc. How do i go about this? I am following a tutorial,
Dojo how to make a widget
Please help me out.
Thanks
First. I'am not good at english, but will do at my best.
This is the path of my widget.
Here. The important code in the js file that must declare.
dojo.provide("gissoft.dijit.widgetOam");
dojo.require("dojo.parser");
dojo.require("dijit._Widget");
dojo.require("dijit._Templated");
dojo.declare("gissoft.dijit.widgetOam", [dijit._Widget, dijit._Templated], {
widgetsInTemplate: true,
basePath: dojo.moduleUrl("gissoft.dijit"),
templatePath: dojo.moduleUrl("gissoft.dijit", "templates/widgetOam.html"),
constructor: function () {
},
postMixInProperties: function () {
},
postCreate: function () {
},
startup: function () {
}
});
And in file widgetOam.html(templatePath)
<div> <!-- do not add tag <html> , <head> , <body> but must have <div> first -->
Hello World.
</div>
And this is how to call widget from my Default.aspx
You must add this before you call the dojo library
<script>
djConfig = {
parseOnLoad: true,
baseUrl: './',
modulePaths: { 'gissoft.dijit': 'js/gissoft/dijit' }
};
</script>
And in the body
<body class="tundra">
<form id="form1" runat="server">
<div>
<div data-dojo-type="gissoft.dijit.widgetOam"></div>
</div>
</form>
</body>
If I understood correctly, you are asking about how to include another widgets within your custom widget. If that's the case, then we have to modify OammieR's answer a bit, as it's not complete in regards to your question.
To include other widgets within your custom widget, you should include them in your widget declaration:
dojo.provide("gissoft.dijit.widgetOam");
dojo.require("dijit.form.Button"); //<- this the standard widget you want to have in your widget
dojo.require("dojo.parser");
dojo.require("dijit._Widget");
dojo.require("dijit._Templated");
dojo.declare("gissoft.dijit.widgetOam", [dijit._Widget, dijit._Templated], {
widgetsInTemplate: true,
basePath: dojo.moduleUrl("gissoft.dijit"),
templatePath: dojo.moduleUrl("gissoft.dijit", "templates/widgetOam.html"),
particularly important is the "widgetsInTemplate: true" part which tells the parser to expect the widgets inside the widget.
Then you just include the HTML markup for the particular widget you'd like to include in your widget's template.
<div> <!-- do not add tag <html> , <head> , <body> but must have <div> first -->
<button data-dojo-type="dijit.form.Button" type="button" data-dojo-attach-point="_innerWidget" data-dojo-attach-event="ondijitclick:_onClick">Yo!</button>
</div>
dojoAttachPoint is useful so you can get a reference to this widget straightaway in your widget's implementation without getting a reference via dijit.byId('').
Hope this helps.

Categories

Resources