Using external javascript libraries

3035
5
09-02-2019 03:40 PM
PaulHaakma
Regular Contributor

I'm wondering if anyone has any tips or tricks around importing and using external javascript libraries within AppStudio?

There are a couple of libraries that I use a lot in Node that I would like to use occasionally in AppStudio that I can't figure out how to import and use. One is moment.js and the other is Turfjs, and there are others too. There was an older version of moment.js that worked but with AppStudio 3.x it stopped working so I had to switch to using Luxon.

If anyone has any tips then please let me know, and/or if you can specifically find a way to get either of those libraries working!

https://momentjs.com/ 

https://turfjs.org/ 

cheers,

-Paul

0 Kudos
5 Replies
StephenQuan1
Esri Contributor

Hi Paul,

I did some troubleshooting but found that the "moment.js" works by default, e.g.

  • Import the with the usual syntax: import "moment.js" as Moment
  • Use the moment() function as per documentation

Here's an example usage:

import QtQuick 2.7
import ArcGIS.AppFramework 1.0
import "moment.js" as Moment

App {
    id: app
    width: 400 * AppFramework.displayScaleFactor
    height: 640 * AppFramework.displayScaleFactor

    Column {
        anchors.fill: parent
        anchors.margins: 10

        spacing: 10

        Text {
            text: JSON.stringify( moment() ) // "2019-09-06T21:46:33.916Z"
        }

        Text {
            text: moment().format('MMMM Do YYYY, h:mm:ss a') // September 7th 2019, 7:47:08 am
        }

        Text {
            text: moment().format("dddd") // Saturday
        }

        Text {
            text: moment().format('YYYY [escaped] YYYY') // 2019 escaped 2019
        }

        Text {
            text: moment().format() // 2019-09-07T07:48:57+10:00
        }
    }
}‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍
PaulHaakma
Regular Contributor

Hi Stephen

Not sure what's happened with the replies in Geonet, I got an email alert with one set of instructions but then when I went to reply online I see a different reply above?

You mention above that moment.js works fine for you, but that's not my experience, it fails to load each time.

However, if I follow your comments from the email alert that I got, it does work! I have pasted that below here in case anyone else experiencing same issues as me....

Hi Paul,

 

I did a small edit to the "moment.js" to make it work.

 

  • I declare a new global variable: var moment;
  • Assign it, moment = global.moment = factory();

 

//! moment.jsvar moment;;(function (global, factory) {    typeof exports === 'object' && typeof module !== 'undefined' ? module.exports = factory() :    typeof define === 'function' && define.amd ? define(factory) :    moment = global.moment = factory()}(this, (function () { 'use strict';//...
0 Kudos
StephenQuan1
Esri Contributor

Hi Paul,

I had numerous attempts at this over the weekend.

The first version I did was the workaround which you got a copy from the email.

However, I found the workaround ugly.

When I retested the "import" as is, I found it to just work with my version of AppStudio.

I will do some further troubleshooting, but, can you tell me which version of Qt you are using?

Stephen

0 Kudos
PaulHaakma
Regular Contributor

Am using AppStudio v4.0.93, which uses Qt v5.12.3.

0 Kudos
StephenQuan1
Esri Contributor

Thanks Paul,

I'm using a similar version.

In one of the troubleshooting sessions, I modified the header of "moment.js" to the following:

//! moment.js

;(function (global, factory) {
    typeof exports === 'object' && typeof module !== 'undefined' ? module.exports = factory() :
    typeof define === 'function' && define.amd ? define(factory) :
    global.moment = factory()
    console.log("typeof(global): ", typeof(global));
    global[ "one" ] = 1;
    global[ "two" ] = 2;
    global[ "three" ] = 3;
    global[ "key" + Math.random() ] = 1;
    console.log("global keys: ", JSON.stringify( Object.keys( global ) ) );
}(this, (function () { 'use strict';
‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍

Then in my app, I imported "moment.js" twice:

import "moment.js" as Moment1
import "moment.js" as Moment2

On the first import, this yielded the following output:

qml: typeof(global):  object
qml: global keys:  ["moment","one","two","three","key0.3286030239782699"]‍‍‍‍

On the second import, this yielded the following:

qml: typeof(global):  object
qml: global keys:  ["moment","one","two","three","key0.3286030239782699","key0.7088453144951244"]‍‍

i.e. what appears to be happening, is the value of "this" which later becomes "global" refers to Javascript object in the global namespace. What the moment.js library is trying to do is install a moment() as a function in the global namespace. For good measure, I wanted to see if I can put some random keys in the global namespace as well, and, yes, that appears to have worked too.

This means when you use these objects in your app, you don't need to use the specifier, i.e. I didn't use either Moment1 nor Moment2. I just referred to the moment() function directly.

Similarly, for the other items I added in the global namespace, I could access them too, e.g.

Text {
    text: three // 3
}

If you still cannot get it to work, then, yes, feel free to refer to my workaround, i.e.

//! moment.js

var moment

;(function (global, factory) {
    typeof exports === 'object' && typeof module !== 'undefined' ? module.exports = factory() :
    typeof define === 'function' && define.amd ? define(factory) :
    global.moment = factory()
    moment = global.moment
}(this, (function () { 'use strict';
‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍

Then, in your app, use the workaround as follows:

import QtQuick 2.7
import QtQuick.Controls 2.1

import ArcGIS.AppFramework 1.0
import "moment.js" as Moment

App {
    id: app
    width: 400
    height: 640

    property var moment: Moment.moment

    Text {
        text: moment().format("dddd")
    }
}

Stephen

0 Kudos