0

I am attempting to port an enterprise webforms app to blazor server. Mapping is what I'm currently stuck on. I am trying to import the Leaflet js library but i can't get it and it's dependencies to all resolve. We use mapping in a modal that sits in the (previously MasterPage) MainLayout.razor file. An input type image triggers the modal to appear with the maps.

I have a function that initiates the map

    private IJSObjectReference Map;
    protected override async Task OnAfterRenderAsync(bool firstRender)
            {
                if (firstRender)
                {
                    Map = await Script.InvokeAsync<IJSObjectReference>("import", "./scripts/MyMap.js");
                    await Map.InvokeVoidAsync("ShowMap", some, str, parms);
                }
            }

That block calls the intial function which adds map markers (custom tooltips that contain user input and a lot of other things). Within that function is where things go awry.

import * as L from './leaflet/leaflet-src.esm.js';
import './leaflet/markercluster-src.js'
import './leaflet/esri-leaflet-vector.'
import './leaflet/esri-leaflet-vector.js';

export function ShowMap(some, rand, str) {
    
    var wayPoints = {};

    var popup = L.DomUtil.get('mappin');
    if (popup != null)
        popup._leaflet_id = null;
    var lat = '39.8283';
    var lng = '98.5795';

    var map = L.map('mappin', { center: [lat, lng], zoom: 10 }); 

    var markers = new L.MarkerClusterGroup();

    var markersList = [];

    // request public vector tile layer from ArcGIS Online
    L.esri.Vector.vectorTileLayer("http://arcgiswebsitethatwegetvectortilesfrom.lmao", {

        // add service to map
    }).addTo(map);
    map._layersMaxZoom = 19;
    map._layersMinZoom = 2;


//ommitted code that does the custom stuff


    map.addLayer(markers);


}

The problem is that trying to import leaflet I have to use the leaflet esm and import * as L to get the L object, but then everything else that relies on L will fail during the import because L won't have a definition for this or that, all because I am using the leaflet-src.esm.js file. Markercluster and Esri Vector both rely on L and markercluster doesn't have a module that I can find. I tried dissecting the npm leaflet.markercluster.esm package and it 'worked' but then I got stuck on the Esri leaflet package needing the L reference as well. I'm new to the js reference world. I'm used to being able to throw a script tag at the top of the page and moving on with life. Blazor makes this a lot more difficult. Does anyone have any ideas? End of the day I'm trying to import Leaflet js, markercluster js, esri-vector js and have them all work together OnAfterRenderAsync.

Mamw93
  • 3
  • 2

1 Answers1

0

You should be able to include all scripts inside index.html (or _Layout.cshtml if you are using blazor server side), e.g.:

<body>
    ...
    ...
    
    <script src="js/leaflet.js"></script>

    <script src="https://cdnjs.cloudflare.com/ajax/libs/leaflet.markercluster/1.5.3/leaflet.markercluster.js"
            integrity="sha512-OFs3W4DIZ5ZkrDhBFtsCP6JXtMEDGmhl0QPlmWYBJay40TT1n3gt2Xuw8Pf/iezgW9CdabjkNChRqozl/YADmg==" 
            crossorigin="anonymous" 
            referrerpolicy="no-referrer"></script>

    <script src="https://unpkg.com/esri-leaflet@3.0.8/dist/esri-leaflet.js"
            integrity="sha512-E0DKVahIg0p1UHR2Kf9NX7x7TUewJb30mxkxEm2qOYTVJObgsAGpEol9F6iK6oefCbkJiA4/i6fnTHzM6H1kEA=="
            crossorigin=""></script>

    <script src="https://unpkg.com/esri-leaflet-vector@4.0.0/dist/esri-leaflet-vector.js"
            integrity="sha512-EMt/tpooNkBOxxQy2SOE1HgzWbg9u1gI6mT23Wl0eBWTwN9nuaPtLAaX9irNocMrHf0XhRzT8B0vXQ/bzD0I0w=="
            crossorigin=""></script>
</body>

And use it "normally" without importing anything:

export function ShowMap(some, rand, str) {
    
    var wayPoints = {};

    var popup = L.DomUtil.get('mappin');
    if (popup != null)
        popup._leaflet_id = null;
    var lat = '39.8283';
    var lng = '98.5795';

    var map = L.map('mappin', { center: [lat, lng], zoom: 10 }); 

    var markers = new L.MarkerClusterGroup();

    var markersList = [];

    // request public vector tile layer from ArcGIS Online
    L.esri.Vector.vectorTileLayer("http://arcgiswebsitethatwegetvectortilesfrom.lmao", {

        // add service to map
    }).addTo(map);
    map._layersMaxZoom = 19;
    map._layersMinZoom = 2;


//ommitted code that does the custom stuff


    map.addLayer(markers);


}
Dimitris Maragkos
  • 8,932
  • 2
  • 8
  • 26
  • I’d rather not because then the script loads with each component call. I don’t want to always load 5 JS files when they’re only needed for one modal. – Mamw93 Oct 01 '22 at 09:54
  • Blazor creates Single-page applications. In a SPA, a page refresh never occurs. Instead, all necessary HTML, JavaScript, and CSS code is retrieved by the browser with a single page load. And even if the user refreshes the page, the scripts would be cached by the browser. – Dimitris Maragkos Oct 01 '22 at 10:00
  • You can also try a solution like this: https://www.geekinsta.com/add-javascript-in-blazor-components/ or https://stackoverflow.com/a/58979941 – Dimitris Maragkos Oct 01 '22 at 10:04
  • I suppose that’s going to be the only solution but it seems unnecessary. I get that blazor is SPA but when navigating to a new component it does seem that the DOM is 100% reloaded. Cached ha files or not always loading heavy mapping js files seems not very efficient when 95% of users don’t ever interact with the map modal. The frustrating part is that I can load in other JS dynamically but this library is being a PITA. – Mamw93 Oct 01 '22 at 10:24
  • Try this: https://pastebin.com/Nkrejs9r. I think it works but I don't have an API key to test. Change paths based on where you put the libraries. – Dimitris Maragkos Oct 01 '22 at 12:40
  • 1
    I FINALLY GOT IT FIGURED OUT. You're pastebin along with this https://stackoverflow.com/questions/54022946/leafletjs-cannot-set-property-l-of-undefined paved the way. Thank you very much for your help. I'd kiss you if I could. – Mamw93 Oct 01 '22 at 15:09