AMD import type

So to begin with I really do love this language and everything that surrounds it. The community is great as well. I just have a question in regards to AMD import style as my established module and defined types seem to be confusing me more. So far I have:

@bs.module("esri-loader") external loadModules: (array<string>) => promise<'a> = 
"loadModules"

this should let me do

let binder = EsriBindingTest.loadModules(["esri/Graphic"])
->Js.Promise.then_(
Graphic  => 
{
       //inner logic primarily methods
})

but the problem keeps returning errors such as promise errors and types missing. I am trying to use the 3rd party esri-loader library for geospatial analysis and this is kind of a sample:

loadModules(['esri/views/MapView', 'esri/WebMap'])
  .then(([MapView, WebMap]) => {
    // then we load a web map from an id
    var webmap = new WebMap({
      portalItem: { // autocasts as new PortalItem()
        id: 'f2e9b762544945f390ca4ac3671cfa72'
      }
    });
    // and we show that map in a container w/ id #viewDiv
    var view = new MapView({
      map: webmap,
      container: 'viewDiv'
    });
  })
  .catch(err => {
    // handle any errors
    console.error(err);
  });

any help is much appreciated!

maybe I don’t understand your problem but its just seems to be that promise does not exist, use Js.Promise.t<'a>

@module("esri-loader") external loadModules: (array<string>) => Js.Promise.t<'a> = 
"loadModules"

And be careful with Js.Promise.then_, it has a “subject last” signature, so you need to use |> pipe operator or consider using rescript-promise to have better syntax

open Js.Promise
let binder = EsriBindingTest.loadModules(["esri/Graphic"])
|>then_(...)
|>catch(...)

I assume you’re Reason Discord user ‘stalwart#8925’, check my answer there.

Don’t use the |> operator. It’s deprecated for ReScript usage.
See the Promise docs how to use the api with -> + _:

open Js.Promise
let binder = EsriBindingTest.loadModules(["esri/Graphic"])
->then_(() => {...}, _)
->catch(() => {...}, _)

The rescript-promise bindings will hopefully be upstreamed to the Js module soon to have a better out of the box experience.

Would you be able to briefly explain why?

Hi @benadamstyles deprecation info is here:

Thanks! It doesn’t however explain why it’s deprecated. I can’t see any reason why the two pipe operators shouldn’t coexist. Both are useful in different situations.

It’s deprecated because we are enforcing consistent styles for all APIs. E.g the stdlib will eventually follow the -> approach in all of its modules. We also don’t want our users to choose between different pipe operators, because it’s confusing at best whenever you are hitting a pipe-last vs pipe-first based third-party package.

2 Likes

I didn’t know this way :ok_hand:

1 Like

@ryyppy I have seemed to get it to work but the type bindings for let’s say defining an external method that does the same functionality is a bit tricky. I do have to define it as a method but it returns a promise but I do not need to define a new Promise initiator within a variable so this should work but it’s bouncing back a bit:

 EsriLeafletBinding.loadModules(["esri/config","esri/Map"])
->Js.Promise.then_(value => {
Js.Promise.resolve(value)
 })

And this is what it compiles to:

var loadModules = new Promise((function (resolve, reject) {

                  return resolve((EsriLoader.loadModules([

                                    "esri/config",

                                    "esri/Map"

                                  ]), undefined));

                }));

          var loaded = loadModules.then(function (value) {

                console.log(value);

                return Promise.resolve(value);

              });

You forgot to provide the _ in the last argument position of then_, no?

 EsriLeafletBinding.loadModules(["esri/config","esri/Map"])
->Js.Promise.then_(value => {
Js.Promise.resolve(value)
 }, _) //<--- note the _

This binding is really busted because it’s still taking the promise value in the last argument position. Luckily we will fix this up in the next few weeks.

Yeah it still is kind of an issue. I am just doing the @arcgis/core imports instead and might come up with a custom method that fixes the AMD issue. As it is a bit difficult to correctly define it within rescript as you would with other JS methods and so on.

Can you please prepare a workable playground link with your latest code so we can help troubleshooting? Your latest output snippet shows a resolve(EsriLoader.loadModules), which looks wrong.

Sure here it is load mods example

okay.

So this:

@module(
  "https://cdn.jsdelivr.net/npm/esri-loader@3.0.0/dist/umd/esri-loader.min.js"
)
@val
external loadModules: array<string> => Js.Promise.t<'a> = "loadModules"

loadModules(["esri/config"])->Js.Promise.then_((deps) => {
  switch deps {
    | [esriConfig] =>
      Js.log("do something with the esriConfig")
      Js.log(esriConfig)
    | _ => Js.log("not all deps available")
  }
  Js.Promise.resolve()
}, _)
->ignore

Playground Link

would essentially give you this:

var EsriLoaderMinJs = require("https://cdn.jsdelivr.net/npm/esri-loader@3.0.0/dist/umd/esri-loader.min.js");

var __x = EsriLoaderMinJs.loadModules(["esri/config"]);

__x.then(function (deps) {
      if (deps.length !== 1) {
        console.log("not all deps available");
      } else {
        var esriConfig = deps[0];
        console.log("do something with the esriConfig");
        console.log(esriConfig);
      }
      return Promise.resolve(undefined);
    });

I don’t know much about esri-leaflet, but this output looks fine to me.

Is the ES6 module import style not working? Just wondering why you are trying to use AMD style…

@ryyppy Thank you! Just needed to think about it, the ignore part was messing with me. But here is the working part:

loadModules(["esri/config"])->Js.Promise.then_((deps) => {

        switch deps {

        | [esriConfig] => 

            esriConfig["apiKey"]="keygiven" 

            Js.log(esriConfig)

        | _ => Js.log("not working")

        }

        Js.Promise.resolve()

      },_)->ignore

Also will release a library for it. Thanks again @ryyppy @yawaramin and everyone for the help also @yawaramin I did try that but I need to create an easier way to dynamically load maps and layers with specific data. Loading it this way reduces a lot of boilerplate but I think they primarily released the other way to make it easier to integrate it easier within already created applications for streamlining the integration process.

1 Like