I have a page that gets the current location from the device's location services. I want to display this in a map, zoomed into the immediate area. I've tried doing this from OnParameterSetAsync, or OnAfterRenderAsync using ZoomToGeographicAsync, but neither works. The problem seems to be that my reference to the map component is null in these calls. I added a button that calls the same code when pressed and this works fine, but I'd like it to be done automatically. Short of adding a timer event to repeatedly check until it is safe to use the reference, how can I get this to work correctly?
I'm binding the reference like follows:
<GeographicMap @ref="@geoMap" Width="100%" Height="240px" Zoomable="true"> <GeographicSymbolSeries DataSource="locs" MarkerType="MarkerType.Triangle" LatitudeMemberPath="Lat" LongitudeMemberPath="Lon" MarkerBrush="Red" MarkerOutline="Black" /> </GeographicMap>
Thanks Andrew, that makes sense as I'd had that once or twice myself. I'd suspected it was something along those lines, but hadn't had a chance to investigate further yet
Hello Kevin,
The Task.Delay was originally a way to prevent an InvalidOperationException in that the GeographicMap wasn’t “ready” from its base renderer. I have since found a better way, though, as I did not realize there was an EnsureReady method on the map. As such, I would recommend continuing with the setter of the GeoMapRef, but call this instead of the Task.Delay:
_geoMap.EnsureReady().ContinueWith((t) => OnMapRender());
I hope this helps! Please let me know if you have any other questions or concerns on this matter.
Why the Task.Delay, by the way? Is there a period after the reference is set when the component is not fully available? I notice the solution occasionally fails (no error, but no zoom applied), but I've not investigated why yet, so perhaps there's a timing related issue
Ah yes, nice way to work around it, better than the mess I came up with timer events for sure.
While it is true that the Angular IgrGeographicMap works a bit more reliably for this behavior, I believe we can attribute this to Angular exposing an override for ngAfterViewInit. This reliably happens at the point where the ViewChild is already referenced. In Blazor, the equivalent of this is essentially the OnAfterRender override for the page, but as you have noted, this can happen before the GeographicMap component is actually referenced into its property.
I have been experimenting with different ways of getting the map to zoom in on load, and the most reliable way I have found so far is actually to do something with the setter of the GeographicMap reference property that you define. Something like this appears to work reliably on my end where “GeoMap” is the “ref” of the GeographicMap object:
private GeographicMap _geoMap; public GeographicMap GeoMap { get { return _geoMap; } set { _geoMap = value; if (_geoMap != null) { Task.Delay(500).ContinueWith((t) => OnMapRender()); } } } public void OnMapRender() { this.GeoMap.ZoomToGeographic(new Rect(100, -40, new Size(50, 25))); StateHasChanged(); }
Please let me know if you have any other questions or concerns on this matter.