fis-sst / BlazorMaps

BlazorMaps is a Blazor library that provides a C# interface for maps provided by Leaflet.js library. It includes several Leaflet.js features which are easily accessible from C# level within a project and it does not require any use of JavaScript.
https://fis-sst.pl/en
MIT License
71 stars 26 forks source link

Exception adding Marker #14

Open Webreaper opened 3 years ago

Webreaper commented 3 years ago

Describe the bug I've created a map panel based on your readme, and am adding a marker, but I get this exception:

[23:18:32.700-.NET ThreadPool Worker-WRN] Unhandled exception rendering component: Cannot read properties of null (reading 'addLayer')
TypeError: Cannot read properties of null (reading 'addLayer')
    at i.addTo (https://unpkg.com/leaflet@1.7.1/dist/leaflet.js:5:63275)
    at http://localhost:6363/_framework/blazor.server.js:1:3501
    at new Promise (<anonymous>)
    at Tt.beginInvokeJSFromDotNet (http://localhost:6363/_framework/blazor.server.js:1:3475)
    at http://localhost:6363/_framework/blazor.server.js:1:71783
    at Array.forEach (<anonymous>)
    at Tt._invokeClientMethod (http://localhost:6363/_framework/blazor.server.js:1:71769)
    at Tt._processIncomingData (http://localhost:6363/_framework/blazor.server.js:1:69811)
    at bt.Tt.connection.onreceive (http://localhost:6363/_framework/blazor.server.js:1:64211)
    at WebSocket.o.onmessage (http://localhost:6363/_framework/blazor.server.js:1:48527)

My code is:

    private Map mapRef;
    private LatLng firstMarkerLatLng;
    private Marker marker1;

   protected override async Task OnAfterRenderAsync(bool firstRender)
    {
        if( firstRender )
        {
            await AddMarkers();
        }
    }

    private async Task AddMarkers()
    {
        firstMarkerLatLng = new LatLng(51.506130, -0.090270);
        marker1 = await MarkerFactory.CreateAndAddToMap(firstMarkerLatLng, mapRef);
    }

If I don't call AddMarkers the map renders fine.

Any ideas? Did I miss something?

jczerosb commented 3 years ago

I had similar issue. In my case it is related to the nature of Blazor Events order. Here have to consider Page and Component Events. Page OnAfterRenderAsync fires before Map Component OnAfterRenderAsync, so mapRef is not available at Page Event, but it will be available after Component event.

You have to use EventCallback "AfterRender" of Map component, it will fire only at fisrtRender. On your page in Map component set "AfterRender" parameter and point to a sub, here I named MapAfterRender <Map @ref="mapRef" MapOptions="@mapOptions" AfterRender="@MapAfterRender"></Map>

Then in page code make "MapAfterRender" sub

private async Task MapAfterRender()
  {
    LatLng myOrigin = new LatLng(51.506130, -0.090270);
    await this.MarkerFactory.CreateAndAddToMap(myOrigin, mapRef);
    // Or simply call your AddMarkers
    // await AddMarkers();
  }

After MapAfterRender get executed you ready to do anything you want, mapRef is already set. This is only necessary when you want load your map and place objects immediately without user iteration with map.

Webreaper commented 3 years ago

I spent a lot of time messing around with the control, trying to get it to work with updates, and to be able to write the code in a way that wasn't horrendously hacky, and in the end gave up and switched to the Syncfusion Map component, which just worked out of the box without any messing around, race conditions or exceptions.

You guys should probably re-write the way it works so that non-standard stuff like component AfterRender hooks aren't required. Or, at the very least, write some sample code that demonstrates how it can be used in a fully interactive scenario where the marker creation is dynamic and passed into the component that contains the map via Parameters etc. Currently, it's unusable for anything other than the most simple scenario. It would also be much simpler if you used proper parameters etc for setting the markers and layers up, rather than having to define a @ref for the mapRef, which immediately makes all of the standard Blazor override methods unusable. Have a look at the way Syncfusion do it in their control.... :)

jczerosb commented 3 years ago

Glad now you found an alternative that fit your needs. On the other hand, it does not help me in any way because in Syncfusion Map there is no support for drawing shapes. Of course agree that should had a sample or note, so we dot not have to play around trying to figure out what´s going on.