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

Display multiple maps on page within child component throws an error #393

Open
aryehsilver opened this issue Jan 10, 2025 · 16 comments
Open

Comments

@aryehsilver
Copy link

aryehsilver commented Jan 10, 2025

I'm trying to show multiple cards on a page, each with a map within. If I use this code it works fine:

@foreach (int item in Enumerable.Range(1, 8)) {
  <GoogleMap Id="@($"map-{item}")" Height="300px" Options="_mapOptions" />
}

However, if I move the GoogleMap element into a child component so the code then looks like this:

@foreach (Property property in TheClient.Properties) {
  <MapCard Property="property" />
}

And the child component is this:

<div class="card mb-3 round-it overflow-hidden property cursor-pointer">
  <div class="card-img rounded-0 position-relative overflow-hidden" style="height: 150px;">
    <GoogleMap Id="@($"map-{Property.Id}")" Options="_mapOptions" Height=""175px" />
    <div class="position-absolute" style="inset: 0;"></div>
  </div>

  <div class="card-body p-3 pb-2">
    <div>
      <div class="fw-bold address">@Property.Name</div>
    </div>
  </div>
</div>

@code {
  [Parameter]
  public Property Property { get; set; } = default!;
  private MapOptions _mapOptions = default!;

  protected override Task OnInitializedAsync() {
    _mapOptions = new() {
      Zoom = Property != null ? 17 : 5,
      Center = new LatLngLiteral() {
        Lat = Property != null ? Property.Lat : 53.6865494,
        Lng = Property != null ? Property.Lng : -2.1476396
      },
      MapTypeId = MapTypeId.Roadmap
    };

    return InvokeAsync(StateHasChanged);
  }
}

Then I get the following error:

Microsoft.AspNetCore.Components.WebAssembly.Rendering.WebAssemblyRenderer[100]
      Unhandled exception rendering component: Property 'Map' not found
      Error: Property 'Map' not found
          at stringToFunction (https://localhost:7365/_content/BlazorGoogleMaps/js/objectManager.js:8:23)
          at Object.createObject (https://localhost:7365/_content/BlazorGoogleMaps/js/objectManager.js:374:35)
...

If I open a page that has a single map, and only then open a page with multiple, then no error occurs and it shows all the maps.

@aryehsilver
Copy link
Author

I have created a minimal reproducible example here.
API keys removed from Program.cs files.

@valentasm1
Copy link
Collaborator

Why you need this part <div class="position-absolute" style="inset: 0;"></div> if you remove it it works.
Also you have two double quotes Height=**""**175px"

@aryehsilver
Copy link
Author

I added that as an overlay so the user can't zoom the map since it's on a card. They need to open the full view in order to use the map. It has no effect whatsoever on the map rendering. If I remove it still throws an error.
The double quote is only there since I copied the code from the main project that has a condition in there. Fixing the double quotes doesn't solve the issue.

@aryehsilver
Copy link
Author

I've updated the repo with the double quotes and overlay removed.

@aryehsilver
Copy link
Author

My guess is it has something to do with how it is rendered, but I can't figure out what and why.

@valentasm1
Copy link
Collaborator

I get this error while trying to run client. What i am missing?

WasmAppHost --use-staticwebassets --runtime-config C:\Dev\My\temp\BlazorMapFailingMultiple\GMapT\GMapT\GMapT.Client\bin\Debug\net9.0\GMapT.Client.runtimeconfig.json
Error: Cannot find runtime config at C:\Dev\My\temp\BlazorMapFailingMultiple\GMapT\GMapT\GMapT.Client\bin\Debug\net9.0\GMapT.Client.runtimeconfig.json

@aryehsilver
Copy link
Author

Try to run it using F5 in Visual Studio or VS Code - that's how I run it. I don't use those commands.

(I can't find such a file in my folder either, so our builds are the same:)
image

@valentasm1
Copy link
Collaborator

valentasm1 commented Jan 13, 2025

Was playing around for 1h and couldnt find anything.
Ugly hack to have bool flag and set it to true like this and if true only then draw component

protected override async Task OnAfterRenderAsync(bool firstRender)
{
    if (firstRender)
    {
        await Task.Delay(10);
        DrawMap = true;
        StateHasChanged();
    }
}

@aryehsilver
Copy link
Author

Unfortunately that doesn't solve it either 😓
Still get the same error with the bool.
I appreciate you trying to help.

@aryehsilver
Copy link
Author

Did it work for you adding that check?

@valentasm1
Copy link
Collaborator

Why it acts like this. Startup solution. It works. Stop. Start again. It dont works.
Despite that i found working ugly ugly hack. Possible make a bit nicer, but idea is the same.
I really though @rendermode @(new InteractiveAutoRenderMode(prerender: false)) will solve it.

cs

namespace GMapT.Client.Pages;
public partial class MultiCard
{
    public bool Draw { get; set; }
    public TClient TheClient { get; set; } = new();
    protected override async Task OnAfterRenderAsync(bool firstRender)
    {
        if (firstRender)
        {
            Draw = true;
            await Task.Delay(10);
            TheClient.Properties.Add(new() { Id = 1, Name = "Property 1", Lat = 53.6865494, Lng = -2.1476396 });
            StateHasChanged();
            await Task.Delay(10);
            TheClient.Properties.Add(new() { Id = 2, Name = "Property 2", Lat = 52.3823494, Lng = -1.2539326 });
            await Task.Delay(10);
            TheClient.Properties.Add(new() { Id = 3, Name = "Property 3", Lat = 51.9147064, Lng = -2.5837012 });
            StateHasChanged();
        }
    }
}

public class TClient
{
    public List<Property> Properties { get; set; } = new List<Property>();
}

public class Property
{
    public int Id { get; set; }
    public string Name { get; set; } = "";
    public double Lat { get; set; }
    public double Lng { get; set; }
}

Razor

@page "/multi-card"

<PageTitle>Multi Test</PageTitle>

<h1>Multi test</h1>

@if (Draw)
{
    <div style="display: grid;
      place-content: center;
      grid-template-columns: repeat(auto-fill, minmax(300px, 1fr));
      gap: 1rem;">
        @foreach (Property property in TheClient.Properties)
        {
            <MapCard Property="property" />
        }
    </div>
}

@aryehsilver
Copy link
Author

Oooh that is a horrible solution but it does work. Although the first time I ran it it still broke.
But it will get even worse when the properties are dynamic and there can be tens of them per client.

@valentasm1
Copy link
Collaborator

Maybe serve that page from serverside. There are registered couple similar issues here, but so far no one find solution. If i knew what to do i will implement it without complain.

@aryehsilver
Copy link
Author

Setting @rendermode InteractiveServer has the same issue.
This issue seems to be to do with the way Blazor renders the components. Possibly to do with the fact that they are rendered from in -> out, child then parents.

At the moment I'm stuck as I don't have any working solution to actually use this.

@Nickztar
Copy link
Contributor

Not sure what the issue here is but this seems like a perfect case for using:
https://developers.google.com/maps/documentation/maps-static/overview
Maybe you need the interactivity for something but using the Static map would be a bit easier since you wouldn't need to handle anything extra to prevent zoom etc. It's just a image.

If that doesn't work for your case, I can try help figure out the issue here.

@aryehsilver
Copy link
Author

@Nickztar this is perfect thank you. This is OK in my case.

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

3 participants