Select to view content in your preferred language

Error: Calcite-Button sometimes doesn't load "Failed to construct 'URL': Invalid base URL"

302
4
05-30-2024 01:26 AM
abrown8
New Contributor III

Hi all

My calcite-button component sometimes does not load (it's annoyingly temperamental). The error is receive is: "Failed to construct 'URL': Invalid base URL".

Any help in fixing this error would be appreciated!

I am using React (vite) and I want a button that opens a popover, which then has inputs to filter the feature layer.

Additionally, the commented out layer.Views.find() does not work and I instead have to hard code layerView.items[0] which isn't ideal.

Code sample is below:

Header.jsx which is called as a component in Main.jsx

import React, { useState, useEffect } from 'react';
import './styles/header.css';
import './styles/style.css';
import * as reactiveUtils from "@arcgis/core/core/reactiveUtils.js";
import LayerView from "@arcgis/core/views/layers/LayerView.js";
import "@esri/calcite-components/dist/calcite/calcite.css";
import "@esri/calcite-components/dist/components/calcite-button";
import "@esri/calcite-components/dist/components/calcite-popover";
import "@esri/calcite-components/dist/components/calcite-input";
import "@esri/calcite-components/dist/components/calcite-input-number";
import "@esri/calcite-components/dist/components/calcite-input-message";
import { CalciteButton, CalcitePopover, CalciteInputNumber, CalciteInputMessage } from "@esri/calcite-components-react";


async function filterConfidence(webmap, view, minVal, maxVal) {
    const psLayer = webmap.layers.find((layer) => layer.title === "PS");

    const psLayerView = view.layerViews.items[0];
    //const psLayerView = view.layerViews.find((layer) => layer.title === "PS");
    console.log(psLayerView)
    await reactiveUtils.whenOnce(() => !LayerView.updating);

    let expression = ''
    console.log(minVal, maxVal);
    if ((minVal !== null || minVal !== '') && (maxVal !== null || maxVal !== '')) {
        expression = "coherence <= " + maxVal + " AND coherence >= " + minVal
        console.log(1)
    } else if ((minVal !== null || minVal !== '') && (maxVal === null || maxVal === '')) {
        expression = "coherence >= " + minVal
        console.log(2)
    } else if ((maxVal !== null || maxVal !== '') && (minVal === null || minVal === '')) {
        expression =  "coherence <= " + maxVal
        console.log(3)
    }

    console.log(expression)
    try {
        if (expression !== '') {
            psLayerView.filter = {
                where: expression
            };
        }
    } catch(error) {
        console.log("Filter failed: ", error);
    }

}

function Header(props) {
    const [minValue, setMinValue] = useState(null);
    const [maxValue, setMaxValue] = useState(null);

    function InputMessage({minValue, maxValue}) {
        if (maxValue < minValue) {
            return <CalciteInputMessage icon="exclamation-mark-triangle" >Should be greater or equal to {minValue} </CalciteInputMessage>
        }
    }

    useEffect(() => {filterConfidence(props.webmap, props.view, minValue, maxValue)}, [minValue, maxValue])
    

    return (
        <div id="header-panel">
            <div className="header-title">
                ENVI Inform Ground Motion Monitoring Service  
            </div>
            <div id='header-container'>
                <CalcitePopover label="Set confidence filter" reference-element="popover-button" auto-close placement="bottom" overlay-positioning="fixed" offset-distance="0" offset-skidding="0" pointer-disabled calcite-hydrated>
                    <div className='popover-container'>
                        <div className='popover-selectors'>
                            <div className='flex items-baseline'>
                                <div className='flex-auto'>
                                    <div className='flex'>
                                        <CalciteInputNumber placeholder="Minimum Confidence" alignment='start' number-button-type='vertical' scale='m' status='idle' step={0.1} min={0} max={1}
                                            value={minValue} onCalciteInputNumberChange={(e) => setMinValue(e.target.value)} />
                                        <CalciteInputNumber placeholder="Maximum Confidence" alignment='start' number-button-type='vertical' scale='m' status='idle' step={0.1} min={0} max={1}
                                            value={maxValue} onCalciteInputNumberChange={(e) => setMaxValue(e.target.value)} />
                                            value range: {minValue} to {maxValue}

                                        <InputMessage minValue={minValue} maxValue={maxValue}></InputMessage>
                                    
                                    </div>
                                </div>
                            </div>
                        </div>
                    </div>
                </CalcitePopover>
                <calcite-button appearance="outline-fill" id="popover-button" calcite-hydrated>
                    Filter by Confidence
                </calcite-button>
            </div>
        </div>
    )
}

export default Header;

 

 

4 Replies
RoryMacGregor
New Contributor II

I am also getting the same error when importing Calcite Components and rendering them in React (Vite). Did you make any progress in fixing this issue?

Here's my code:

import React, { useRef, useEffect, useState } from "react";
import { createRoot } from "react-dom/client";
import MapView from "@arcgis/core/views/MapView";
import Map from "@arcgis/core/Map";
import FeatureLayer from "@arcgis/core/layers/FeatureLayer";
import Legend from "@arcgis/core/widgets/Legend";
import PopupTemplate from "@arcgis/core/PopupTemplate";

import "@esri/calcite-components/dist/components/calcite-shell.js";
import "@esri/calcite-components/dist/components/calcite-shell-panel.js";
import "@esri/calcite-components/dist/components/calcite-panel.js";
import "@esri/calcite-components/dist/components/calcite-button.js";
import {
    CalciteShell,
    CalciteShellPanel,
    CalcitePanel,
    CalciteButton,
} from '@esri/calcite-components-react';

import "@esri/calcite-components/dist/calcite/calcite.css";
import "./App.css";

import MapMenu from "./components/MapMenu";

const hubData = {
    agriculture: {
        maps: [
            {
            name: "Caba Partnerships",
            layers: ["https://services3.arcgis.com/Bb8lfThdhugyc4G3/arcgis/rest/services/CaBA_Partnerships/FeatureServer"]
            },
            {
            name: "Rivers",
            layers: ["https://services3.arcgis.com/Bb8lfThdhugyc4G3/arcgis/rest/services/OSOpenRiversCaBA2017/FeatureServer"]
            }
        ]
    }
};

function getLocation(country) {
    switch (country) {
        case "england":
            return [-1.464854, 52.561928]
        case "scotland":
            return [56.4907, -4.2026]
        case "ireland":
            return [-7.6921, 53.1424]
        case "wales":
            return [52.1307, -3.7837]
        case "uk":
            return [52.561928, -1.464854]
        default:
            return [52.561928, -1.464854]
    }
}


// set pretend url params for testing
//window.location.search = "?hub=agriculture&geog=england";





function App() {
    const mapDiv = useRef(null);
    const menuDiv = useRef(document.createElement("div"));
    const menuDivRoot = useRef(null);  // Ref to store the root
    const floatingMenuRef = useRef(null);
    const [menuVisible, setMenuVisible] = useState(true);



    const toggleMenu = () => {
        setMenuVisible(!menuVisible);
    };

    // const urlParams = new URLSearchParams(window.location.search);
    // const hub = urlParams.get("hub") || "agriculture";
    // const geog = urlParams.get("geog") || "england";

    const hub = "agriculture";
    const geog = "england";

    useEffect(() => {
        if (mapDiv.current) {
            /**
             * Initialize application
             */

            const map = new Map({
                basemap: "gray-vector",
            });

            const view = new MapView({
                container: mapDiv.current,
                map: map,
                zoom: 6,
                center: getLocation(geog),
                padding: { left: 49 }
            });

            // Add a legend to the map
            const legend = new Legend({
                view: view,
            });

            view.ui.add(legend, "bottom-right");
            view.popup.defaultPopupTemplateEnabled = true;

            if (!menuDivRoot.current) {
                menuDivRoot.current = createRoot(menuDiv.current);
            }
            menuDivRoot.current.render(
                <MapMenu
                    Maps={hubData[hub].maps}
                    onMapSelect={(layers) => {
                        console.log(`Layers selected: ${layers}`);
                        // Remove all feature layers from the map
                        const layersToRemove = [...map.layers];
                        layersToRemove.forEach((layer) => {
                            console.log("Removing layer");
                            console.log(layer);
                            map.remove(layer);
                        });


                        layers.forEach((url) => {
                            // Add the selected feature layer to the map
                            const featureLayer = new FeatureLayer({
                                url: url
                            });


                            map.add(featureLayer);
                        });


                        // // Zoom to the layer's extent
                        // featureLayer.when(() => {
                        //     view.goTo(featureLayer.fullExtent);
                        // });
                    }}
                />
            );

            // Add the DOM element to the view's UI
            //   view.ui.add(dataViewDiv.current, "top-right");
        }
    }, [menuDiv, mapDiv]);

    useEffect(() => {
        if (floatingMenuRef.current) {
          floatingMenuRef.current.style.display = menuVisible ? 'block' : 'none';
        }
      }, [menuVisible]);


    return (
        <CalciteShell contentBehind>
            <CalciteShellPanel slot="panel-start" displayMode="float">
            <CalciteButton onClick={toggleMenu}>{menuVisible? 'Hide Menu' : 'Show Menu'}</CalciteButton>
                <CalcitePanel className="floatingMenu" ref={floatingMenuRef}>
                    <CalcitePanel className="infoDiv" heading="Information"></CalcitePanel>
                    <div className="menuDiv" ref={menuDiv}></div>
                </CalcitePanel>
            </CalciteShellPanel>
            <CalcitePanel>
                <div className="mapDiv" ref={mapDiv}></div>
            </CalcitePanel>
        </CalciteShell>
    );
}

export default App;
0 Kudos
abrown8
New Contributor III

Unfortunately not. I gave up and switched tracks to MUI components.

0 Kudos
RoryMacGregor
New Contributor II

Thanks for the update, that will likely be the way I go too.

0 Kudos
JasperWieringa
New Member

Are you setting the assetPath in the index.js or main.js or whatever your app loads?
I had a similar issue and when diving into the source code, I found out that this solved my issue:

import { setAssetPath } from '@esri/calcite-components/dist/components';
setAssetPath('https://js.arcgis.com/calcite-components/1.9.2/assets');

 That method is used to manually set the base path where assets can be found. If the script is used as "module", it's recommended to use "import. meta. url", such as "setAssetPath(import. meta. url)". Other options include "setAssetPath(document. currentScript. src)", or using a bundler's replace plugin to dynamically set the path at build time, such as "setAssetPath(process. env. ASSET_PATH)". But do note that this configuration depends on how your script is bundled, or lack of bundling, and where your assets can be loaded from. Additionally custom bundling will have to ensure the static assets are copied to its build directory.

If you have your assets stored locally in the build of your application, you need to use the setAssetPath('your-custom-dir'). In my solution, I just targeted directly to the assets of calcite-components from js.arcgis.com

0 Kudos