Using JS API in extension point

736
3
Jump to solution
03-02-2023 07:31 AM
MatthieuBrisset
New Contributor II

Hello,

In the Experience Builder Dev Edition 1.9, I'm trying to create an AppConfigProcessor extension point in order to modify widget's config programmatically when the application loads.

I followed these following articles and examples :

https://developers.arcgis.com/experience-builder/guide/extension-points/

https://github.com/Esri/arcgis-experience-builder-sdk-resources/blob/d6b9dd8280635ef585b05166d4e485d...

In the process function, I also need to access object from the ArcGIS API, in particular, I need to access esri/config.

Here is my code :

 

 

import esriConfig from 'esri/config'
import { extensionSpec, AppConfig, utils } from 'jimu-core'
import { IMConfig } from '../config'

export default class configProcessor implements extensionSpec.AppConfigProcessorExtension {
  id = 'pp-config'
  widgetId: string

  async process (appConfig: AppConfig): Promise<AppConfig> {
    // configuration of the current widget
    const widgetConfig: IMConfig = appConfig.widgets[this.widgetId].config


    // need to set this property to false
    esriConfig.request.useIdentity = false

    // do stuff with appConfig
    //...
    //
    
    return Promise.resolve(appConfig)
  }
}

 

 

 

The loading of esri/config failed with this error when I start the application :

Load module error. TypeError: window.require is not a function

I tried with other class from the API and I'm still getting the same error.

Here is the manifest.json :

 

 

{
  "name": "config-extension",
  "label": "Configuration Extension",
  "type": "widget",
  "version": "1.10.0",
  "exbVersion": "1.9.0",
  "author": "Matthieu",
  "description": "Configuration de l'application",
  "copyright": "",
  "license": "http://www.apache.org/licenses/LICENSE-2.0",
  "properties": {},
  "translatedLocales": [
    "fr"
  ],
  "extensions": [
    {
      "point": "APP_CONFIG_PROCESSOR",
      "uri": "extensions/ppConfigProcessor"
    }
  ],
  "dependency": ["jimu-arcgis"]
}

 

 


Any ideas ?

Thanks
Matthieu

0 Kudos
1 Solution

Accepted Solutions
MatthieuBrisset
New Contributor II

I find a solution by using the function loadArcGISJSAPIModules

import { loadArcGISJSAPIModules } from 'jimu-arcgis'
import { extensionSpec, AppConfig, utils } from 'jimu-core'
import { IMConfig } from '../config'

export default class configProcessor implements extensionSpec.AppConfigProcessorExtension {
  id = 'pp-config'
  widgetId: string

  async process (appConfig: AppConfig): Promise<AppConfig> {
    // configuration of the current widget
    const widgetConfig: IMConfig = appConfig.widgets[this.widgetId].config

    // load module
    const [esriConfig] = await loadArcGISJSAPIModules(['esri/config'])
    // need to set this property to false
    esriConfig.request.useIdentity = false //ok

    // do stuff with appConfig
    //...
    //
    
    return Promise.resolve(appConfig)
  }
}

 

View solution in original post

3 Replies
Grant-S-Carroll
Esri Contributor

The error occurs because the require library is not loaded when its needed to load in your libraries. 

I was going to ask if you had included the dependancy to arcgis in your code, as I have experienced this before when I forgot to add the dependancy in.

I would check any other custom widgets you have that are using the ArcGIS libraries that the manifest has the correct dependancie set. If you are still having issues, you can add this code to your index.html page. 

Find the index page here.

GrantSCarroll_0-1677780472545.png

Then locate this code 

GrantSCarroll_1-1677780699839.png

This is the code that causes the issue, as its trying to access window.require before its available. You can replace that with this.

if (url.indexOf(window.jimuConfig.arcgisJsApiUrl) === 0 && url !== window.jimuConfig.arcgisJsApiUrl + 'init.js') {
                let amdPath = url.replace(window.jimuConfig.arcgisJsApiUrl, '');
                amdPath = amdPath.replace(/\.js$/, '');

                return new Promise(function (resolve, reject) {
                    if (window.require) {
                        window.require([amdPath], function (m) {
                            const reg = [[], function (_export) {
                                _export({ default: m, __useDefault: true });
                                return {
                                    setters: [],
                                    execute: function () {
                                        _export('default', m);
                                    }
                                };
                            }]

                            resolve(reg);
                        })
                    }
                    else {
                        setTimeout(function () {
                            window.require([amdPath], function (m) {
                                const reg = [[], function (_export) {
                                    _export({ default: m, __useDefault: true });
                                    return {
                                        setters: [],
                                        execute: function () {
                                            _export('default', m);
                                        }
                                    };
                                }]

                                resolve(reg);
                            })
                        }, 1000)
                    }
                });
            }

 

What this code does is check if window.require exists,if it does then continue. If not, wait one second, then try again. You could maybe change this to a while loop, but I've found one second was enough. 

I realise this is a bit of a hack, but if you are stuck and need a last resort then hopefully this helps. You would need to remember to add this in anytime you upgrade. But as its in the dist folder it gets copied out anytime you download the experience to be deployed.

 

MatthieuBrisset
New Contributor II

Thank you for your answer  @Grant-S-Carroll 
I think the solution you proposed should work in 1.9

But we will migrate soon in 1.10 and in 1.10 the index.html contains no javascript. The code you mentioned is now inside the minified file init.js 😞

 

 

MatthieuBrisset_0-1677854925941.png

 

0 Kudos
MatthieuBrisset
New Contributor II

I find a solution by using the function loadArcGISJSAPIModules

import { loadArcGISJSAPIModules } from 'jimu-arcgis'
import { extensionSpec, AppConfig, utils } from 'jimu-core'
import { IMConfig } from '../config'

export default class configProcessor implements extensionSpec.AppConfigProcessorExtension {
  id = 'pp-config'
  widgetId: string

  async process (appConfig: AppConfig): Promise<AppConfig> {
    // configuration of the current widget
    const widgetConfig: IMConfig = appConfig.widgets[this.widgetId].config

    // load module
    const [esriConfig] = await loadArcGISJSAPIModules(['esri/config'])
    // need to set this property to false
    esriConfig.request.useIdentity = false //ok

    // do stuff with appConfig
    //...
    //
    
    return Promise.resolve(appConfig)
  }
}