darnton / LeafletBlazor

Blazor component for interop with Leaflet slippy map library.
30 stars 20 forks source link

With Blazor Server app, exception being thrown when adding Marker in OnAfterRenderAsync #8

Open tek-noid opened 3 years ago

tek-noid commented 3 years ago

I duplicated the existing TestRig with the exception of it being a Server (rather than WebAssembly) App. All works fine.

However, if I try to add markers to the map prior to viewing, the 'marker.AddTo' code throws an exception as JSBinder=null in Marker.CreateJsObjectRef

My noob understanding is that Interop should be available at the point OnAfterRenderAsync is called, but clearly everything isn't ready yet.

Any pointers are welcome.

    protected override async Task OnAfterRenderAsync(bool firstRender)
    {
        await base.OnAfterRenderAsync(firstRender);

        var ll = new LatLng(-42, 175);

        var marker = new Marker(ll, new MarkerOptions
        {
            Title = "Test"
        });

        await marker.AddTo(PositionMap);

    }

Stack

    Darnton.Blazor.Leaflet.dll!Darnton.Blazor.Leaflet.LeafletMap.Marker.CreateJsObjectRef() Line 36 C#
    Darnton.Blazor.Leaflet.dll!Darnton.Blazor.Leaflet.InteropObject.BindJsObjectReference(Darnton.Blazor.Leaflet.LeafletMapJSBinder jsBinder) Line 31   C#
    Darnton.Blazor.Leaflet.dll!Darnton.Blazor.Leaflet.LeafletMap.Layer.AddTo(Darnton.Blazor.Leaflet.LeafletMap.Map map) Line 20 C#
    LeafletServerBlazorTestRig.dll!LeafletServerBlazorTestRig.Pages.Index.OnAfterRenderAsync(bool firstRender) Line 177 C#
darnton commented 3 years ago

The Marker uses the same JS binding as the Map, so you need to make sure that the Map is bound before adding anything else to it.

I have a LeafletMap Razor component and the Map binding happens there

        protected async override Task OnAfterRenderAsync(bool firstRender)
        {
            if (firstRender)
            {
                await Map.BindJsObjectReference(new LeafletMapJSBinder(JSRuntime));
                await TileLayer.AddTo(Map);
            }
        }

The call to Map.BindJsObjectReference needs to happen before the call to Marker.AddTo. The OnAfterRenderAsync method on the parent is called before OnAfterRenderAsync on the child components. If your call to add the marker is on the page containing the map component, it will happen before the JS binding on the map is done, which will cause the problem you see.