Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Removed map HTMLElement from DOM still try to render map #335

Closed
cblanchard-aa opened this issue Jun 17, 2024 · 14 comments
Closed

Removed map HTMLElement from DOM still try to render map #335

cblanchard-aa opened this issue Jun 17, 2024 · 14 comments

Comments

@cblanchard-aa
Copy link

cblanchard-aa commented Jun 17, 2024

Error is thrown when calling Autocomplete.CreateAsync after an async task has been run in the pages OnInitializedAsync method.

Currently you can get around this issue by running your async tasks in the pages OnAfterRenderAsync method.

blazor.web.js:1 [2024-06-17T14:52:34.486Z] Error: Microsoft.JSInterop.JSException: Map: Expected mapDiv of type HTMLElement but was passed null.
InvalidValueError
at _.yj (https://maps.googleapis.com/maps/api/js?libraries=places&key=YOUR_API_KEY&v=weekly&callback=google.maps.__ib__:227:373)
at new Io (https://maps.googleapis.com/maps/api/js?libraries=places&key=YOUR_API_KEY&v=weekly&callback=google.maps.__ib__:298:310)
at Object.createObject (http://localhost:5204/_content/BlazorGoogleMaps/js/objectManager.js:366:27)
at http://localhost:5204/_framework/blazor.web.js:1:3244
at new Promise ()
at y.beginInvokeJSFromDotNet (http://localhost:5204/_framework/blazor.web.js:1:3201)
at gn._invokeClientMethod (http://localhost:5204/_framework/blazor.web.js:1:62841)
at gn._processIncomingData (http://localhost:5204/_framework/blazor.web.js:1:60316)
at connection.onreceive (http://localhost:5204/_framework/blazor.web.js:1:53957)
at i.onmessage (http://localhost:5204/_framework/blazor.web.js:1:82102)
at Microsoft.JSInterop.JSRuntime.InvokeAsync[TValue](Int64 targetInstanceId, String identifier, Object[] args)
at GoogleMapsComponents.Helper.MyInvokeAsync[TRes](IJSRuntime jsRuntime, String identifier, Object[] args)
at GoogleMapsComponents.JsObjectRef.CreateAsync(IJSRuntime jsRuntime, Guid guid, String functionName, Object[] args)
at GoogleMapsComponents.Maps.Map.CreateAsync(IJSRuntime jsRuntime, ElementReference mapDiv, MapOptions opts)
at GoogleMapsComponents.MapComponent.InitAsync(ElementReference element, MapOptions options)
at GoogleMapsComponents.GoogleMap.OnAfterRenderAsync(Boolean firstRender)
at Microsoft.AspNetCore.Components.RenderTree.Renderer.GetErrorHandledTask(Task taskToHandle, ComponentState owningComponentState)

@valentasm1
Copy link
Collaborator

Neven create anything in OnInitializedAsync since map load asyn and could be created after this method.
Use map OnInitializedAsync like here
https://github.com/rungwiroon/BlazorGoogleMaps/blob/master/ServerSideDemo/Pages/MapAdvancedMarkerViewPage.razor#L48

Does it works now?

@StickieBE
Copy link

Neven create anything in OnInitializedAsync since map load asyn and could be created after this method. Use map OnInitializedAsync like here https://github.com/rungwiroon/BlazorGoogleMaps/blob/master/ServerSideDemo/Pages/MapAdvancedMarkerViewPage.razor#L48

Does it works now?

Funny, I've been banging my head against the wall this afternoon with this exact issue.
I will double-check your suggestion first and report back.

@StickieBE
Copy link

StickieBE commented Jun 17, 2024

I doublechecked, and to clarify some more points:

The proposed implementation works, until the page is refreshed.
I did, however, pinpoint the cause of my issue.
Using breakpoints that hide one map or the other, to show a different-sized map for mobile vs desktop causes the mentioned error.

crit: Microsoft.AspNetCore.Components.WebAssembly.Rendering.WebAssemblyRenderer[100]
      Unhandled exception rendering component: Map: Expected mapDiv of type HTMLElement but was passed null.
      InvalidValueError
          at _.yj (https://maps.googleapis.com/maps/api/js?libraries=places&key=API_KEY_OBFUSCATED&v=weekly&callback=google.maps.__ib__:227:373)
          at new Io (https://maps.googleapis.com/maps/api/js?libraries=places&key=API_KEY_OBFUSCATED&v=weekly&callback=google.maps.__ib__:298:310)
          at Object.createObject (http://localhost:25498/_content/BlazorGoogleMaps/js/objectManager.js:366:27)
          at http://localhost:25498/_framework/blazor.webassembly.js:1:2878
          at new Promise (<anonymous>)
          at b.beginInvokeJSFromDotNet (http://localhost:25498/_framework/blazor.webassembly.js:1:2835)
          at Object.vn [as invokeJSJson] (http://localhost:25498/_framework/blazor.webassembly.js:1:58849)
          at http://localhost:25498/_framework/dotnet.runtime.8.0.6.xm0i2q3k8g.js:3:178364
          at Tl (http://localhost:25498/_framework/dotnet.runtime.8.0.6.xm0i2q3k8g.js:3:179198)
          at wasm://wasm/00b2193a:wasm-function[349]:0x1fab4
Microsoft.JSInterop.JSException: Map: Expected mapDiv of type HTMLElement but was passed null.
InvalidValueError
    at _.yj (https://maps.googleapis.com/maps/api/js?libraries=places&key=API_KEY_OBFUSCATED&v=weekly&callback=google.maps.__ib__:227:373)
    at new Io (https://maps.googleapis.com/maps/api/js?libraries=places&key=API_KEY_OBFUSCATED&v=weekly&callback=google.maps.__ib__:298:310)
    at Object.createObject (http://localhost:25498/_content/BlazorGoogleMaps/js/objectManager.js:366:27)
    at http://localhost:25498/_framework/blazor.webassembly.js:1:2878
    at new Promise (<anonymous>)
    at b.beginInvokeJSFromDotNet (http://localhost:25498/_framework/blazor.webassembly.js:1:2835)
    at Object.vn [as invokeJSJson] (http://localhost:25498/_framework/blazor.webassembly.js:1:58849)
    at http://localhost:25498/_framework/dotnet.runtime.8.0.6.xm0i2q3k8g.js:3:178364
    at Tl (http://localhost:25498/_framework/dotnet.runtime.8.0.6.xm0i2q3k8g.js:3:179198)
    at wasm://wasm/00b2193a:wasm-function[349]:0x1fab4
   at Microsoft.JSInterop.JSRuntime.<InvokeAsync>d__16`1[[System.Object, System.Private.CoreLib, Version=8.0.0.0, Culture=neutral, PublicKeyToken=7cec85d7bea7798e]].MoveNext()
   at GoogleMapsComponents.Helper.<MyInvokeAsync>d__10`1[[System.Object, System.Private.CoreLib, Version=8.0.0.0, Culture=neutral, PublicKeyToken=7cec85d7bea7798e]].MoveNext()
   at GoogleMapsComponents.JsObjectRef.CreateAsync(IJSRuntime jsRuntime, Guid guid, String functionName, Object[] args)
   at GoogleMapsComponents.Maps.Map.CreateAsync(IJSRuntime jsRuntime, ElementReference mapDiv, MapOptions opts)
   at GoogleMapsComponents.MapComponent.InitAsync(ElementReference element, MapOptions options)
   at GoogleMapsComponents.GoogleMap.OnAfterRenderAsync(Boolean firstRender)
   at Microsoft.AspNetCore.Components.RenderTree.Renderer.GetErrorHandledTask(Task taskToHandle, ComponentState owningComponentState)

Reverting to a single map means the proposed solution works like a charm.
Perhaps this could be handled better, as it can be confusing.

@valentasm1
Copy link
Collaborator

Do you have sample to reproduce?

@StickieBE
Copy link

Do you have sample to reproduce?

I am working on a reliable one and will report back soon.

StickieBE added a commit to StickieBE/BlazorGoogleMaps that referenced this issue Jun 17, 2024
@cblanchard-aa
Copy link
Author

Neven create anything in OnInitializedAsync since map load asyn and could be created after this method. Use map OnInitializedAsync like here https://github.com/rungwiroon/BlazorGoogleMaps/blob/master/ServerSideDemo/Pages/MapAdvancedMarkerViewPage.razor#L48

Does it works now?

I am loading data that is totally separate from the map, not doing anything with the map in this method.

@StickieBE
Copy link

StickieBE commented Jun 17, 2024

@valentasm1 The above commit/fork is a 1:1 repro of the issue, with 100% accuracy.

The repro steps were added in a later commit:

Steps to reproduce the issue

  1. Checkout the repro fork.
  2. Open the BlazorGoogleMaps.sln.
  3. Set the project to ClientSideDemo.
  4. Start the project.
  5. Navigate to /mapEvents.
  6. Press F12 to open the developer console.
  7. Switch to mobile view.
  8. Refresh the page.
  9. The error should occur.

Note that the solution works perfectly fine when not involving the Mudblazor library, but I wanted to give you a proper repro, as I do think there is room for improvement here.

@cblanchard-aa
Copy link
Author

I doublechecked, and to clarify some more points:

The proposed implementation works, until the page is refreshed. I did, however, pinpoint the cause of my issue. Using breakpoints that hide one map or the other, to show a different-sized map for mobile vs desktop causes the mentioned error.

crit: Microsoft.AspNetCore.Components.WebAssembly.Rendering.WebAssemblyRenderer[100]
      Unhandled exception rendering component: Map: Expected mapDiv of type HTMLElement but was passed null.
      InvalidValueError
          at _.yj (https://maps.googleapis.com/maps/api/js?libraries=places&key=API_KEY_OBFUSCATED&v=weekly&callback=google.maps.__ib__:227:373)
          at new Io (https://maps.googleapis.com/maps/api/js?libraries=places&key=API_KEY_OBFUSCATED&v=weekly&callback=google.maps.__ib__:298:310)
          at Object.createObject (http://localhost:25498/_content/BlazorGoogleMaps/js/objectManager.js:366:27)
          at http://localhost:25498/_framework/blazor.webassembly.js:1:2878
          at new Promise (<anonymous>)
          at b.beginInvokeJSFromDotNet (http://localhost:25498/_framework/blazor.webassembly.js:1:2835)
          at Object.vn [as invokeJSJson] (http://localhost:25498/_framework/blazor.webassembly.js:1:58849)
          at http://localhost:25498/_framework/dotnet.runtime.8.0.6.xm0i2q3k8g.js:3:178364
          at Tl (http://localhost:25498/_framework/dotnet.runtime.8.0.6.xm0i2q3k8g.js:3:179198)
          at wasm://wasm/00b2193a:wasm-function[349]:0x1fab4
Microsoft.JSInterop.JSException: Map: Expected mapDiv of type HTMLElement but was passed null.
InvalidValueError
    at _.yj (https://maps.googleapis.com/maps/api/js?libraries=places&key=API_KEY_OBFUSCATED&v=weekly&callback=google.maps.__ib__:227:373)
    at new Io (https://maps.googleapis.com/maps/api/js?libraries=places&key=API_KEY_OBFUSCATED&v=weekly&callback=google.maps.__ib__:298:310)
    at Object.createObject (http://localhost:25498/_content/BlazorGoogleMaps/js/objectManager.js:366:27)
    at http://localhost:25498/_framework/blazor.webassembly.js:1:2878
    at new Promise (<anonymous>)
    at b.beginInvokeJSFromDotNet (http://localhost:25498/_framework/blazor.webassembly.js:1:2835)
    at Object.vn [as invokeJSJson] (http://localhost:25498/_framework/blazor.webassembly.js:1:58849)
    at http://localhost:25498/_framework/dotnet.runtime.8.0.6.xm0i2q3k8g.js:3:178364
    at Tl (http://localhost:25498/_framework/dotnet.runtime.8.0.6.xm0i2q3k8g.js:3:179198)
    at wasm://wasm/00b2193a:wasm-function[349]:0x1fab4
   at Microsoft.JSInterop.JSRuntime.<InvokeAsync>d__16`1[[System.Object, System.Private.CoreLib, Version=8.0.0.0, Culture=neutral, PublicKeyToken=7cec85d7bea7798e]].MoveNext()
   at GoogleMapsComponents.Helper.<MyInvokeAsync>d__10`1[[System.Object, System.Private.CoreLib, Version=8.0.0.0, Culture=neutral, PublicKeyToken=7cec85d7bea7798e]].MoveNext()
   at GoogleMapsComponents.JsObjectRef.CreateAsync(IJSRuntime jsRuntime, Guid guid, String functionName, Object[] args)
   at GoogleMapsComponents.Maps.Map.CreateAsync(IJSRuntime jsRuntime, ElementReference mapDiv, MapOptions opts)
   at GoogleMapsComponents.MapComponent.InitAsync(ElementReference element, MapOptions options)
   at GoogleMapsComponents.GoogleMap.OnAfterRenderAsync(Boolean firstRender)
   at Microsoft.AspNetCore.Components.RenderTree.Renderer.GetErrorHandledTask(Task taskToHandle, ComponentState owningComponentState)

Reverting to a single map means the proposed solution works like a charm. Perhaps this could be handled better, as it can be confusing

I am not conditionally showing or hiding the map in this instance, it should be on the page in load. However, I am using BlazorBootstrap library, so there could be something else going on there as well.

I will test some things out when I get some time away from work to get more info and see If i can get a sample.

@StickieBE
Copy link

StickieBE commented Jun 17, 2024

I am not conditionally showing or hiding the map in this instance, it should be on the page in load. However, I am using BlazorBootstrap library, so there could be something else going on there as well.

I will test some things out when I get some time away from work to get more info and see If i can get a sample.

For your sanity, I can confirm the proposed solution works fine in NET8, old-school WASM.
Do note that the conditional hiding also is not relevant when done as follows:

@if (_myval)
{
    <GoogleMap Height="400px" @ref="@_map1" Id="map1" Options="@_mapOptions" OnAfterInit="OnAfterInitAsync" />
}
else
{
    <GoogleMap Height="400px" @ref="@_map1" Id="map1" Options="@_mapOptions" OnAfterInit="OnAfterInitAsync" />
}

The above code does not cause the issue.

Perhaps, like you are indicating, we are both doing something that triggers it.
I did take the effort to repro my exact cause, as it might be of use to @valentasm1 to chase down the root cause here.

@valentasm1 valentasm1 changed the title Autocomplete doesn't load after running an async task in OnInitializedAsync Removed map HTMLElement from DOM still try to render map Jun 17, 2024
@valentasm1
Copy link
Collaborator

MudBlazor has some js listeners on resize. It trigger and remove element from DOM. While OnAfterRenderAsync in MapComponent is already trigered with passing ElementReference. When it reaches js ElementReference dont exist since it was removed from DOM by MudBlazor.
All this come from my quick investigation. Need more info for confirmation. Some resources.
MudBlazor/MudBlazor#148 (comment)
src/MudBlazor/TScripts/mudResizeListener.js
src/MudBlazor/TScripts/mudResizeObserver.js

I think solution is one line somewhere in code. Just not sure where exactly :). Probably most stupid one is to add check in js, but i dont like it. It smells :).
I will leave it to you since i am sure you have more knowledge about this

@ScarletKuro
Copy link

MudBlazor has some js listeners on resize. It trigger and remove element from DOM. While OnAfterRenderAsync in MapComponent is already trigered with passing ElementReference. When it reaches js ElementReference dont exist since it was removed from DOM by MudBlazor. All this come from my quick investigation. Need more info for confirmation. Some resources. MudBlazor/MudBlazor#148 (comment) src/MudBlazor/TScripts/mudResizeListener.js src/MudBlazor/TScripts/mudResizeObserver.js

I think solution is one line somewhere in code. Just not sure where exactly :). Probably most stupid one is to add check in js, but i dont like it. It smells :). I will leave it to you since i am sure you have more knowledge about this

This is correct, MudHidden removes the element from the DOM. This might not suit for every component, like this component or another example is file upload. Responsive CSS should be used instead to hide the component.

@valentasm1
Copy link
Collaborator

Dirty workaround could be just ovverider js action window.blazorGoogleMaps.objectManager.createObject
Or use blazorGoogleMapsBeforeStringify somehow
#312
I think there are more ways to solve it in js. Most of them hacky way.
Since it is not related to this library then i am closing issue.
If you have other suggestion please update. Maybe other will find it usefull.

@StickieBE
Copy link

StickieBE commented Jun 18, 2024

I did kind of hijack @cblanchard-aa 's ticket. My bad :)
Thanks for the response @ScarletKuro & @valentasm1, it is very much appreciated.

@cblanchard-aa
Copy link
Author

cblanchard-aa commented Jun 19, 2024

I did kind of hijack @cblanchard-aa 's ticket. My bad :) Thanks for the response @ScarletKuro & @valentasm1, it is very much appreciated.

I appreciate you hijacking it! I am busy trying to build an application for my company :). Appreciate the quick response time and turnaround. The issue is resolved on my end, you guys are awesome!

Edit - for context - workaround posted in my inital comment is the solution that I am rolling with :)

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

No branches or pull requests

4 participants