ngx-leaflet: leaflet map doesn't load tiles after refreshing the page
Hi ya’all,
I recently started to use ngx-leaflet in one project. When I use the following code, I have the problem that the map shows only all map tiles when navigating via my app (using the buttons) to the page. As soon as I reload the page using the reload button from the browser (or as I just enter the url directly), the page show just a small tile and the rest of the area where the map should be visible stays in gray color (see attached picture). Also when I use my phone (iPhone) to display the site, I can’t see the whole map.

I found out that when I resize the browser window manually, the tiles are loaded. So it seem to be a problem with the calculation probably?
Do you have any Idea how to solve this problem?
File map.component.html:
<div leaflet
[leafletOptions]="leafletOptions"
[leafletBaseLayers]="baseLayers"
[leafletLayersControlOptions]="layersControlOptions"
(leafletMapReady)="onMapReady($event)">
</div>
File map.component.css:
div.leaflet-container {
position: absolute !important;
width: 100%;
height: calc(100% - 105px);
}
File map.component.ts:
import { Component, OnInit } from '@angular/core';
import * as L from 'leaflet';
// Open Street Map Definition
const layOsm: L.TileLayer = L.tileLayer('http://{s}.tile.openstreetmap.org/{z}/{x}/{y}.png', {
maxZoom: 19,
attribution: 'Map-Name',
detectRetina: true
});
@Component({
selector: 'gpst-map',
templateUrl: './map.component.html',
styleUrls: ['./map.component.css']
})
export class MapComponent implements OnInit {
// Values to bind to Leaflet Directive
leafletOptions: L.MapOptions = {
zoom: 6,
center: L.latLng(51.163375, 10.447683)
};
baseLayers: {[layerName: string]: L.Layer} = {
'openstreetmap': layOsm
};
layersControlOptions: L.ControlOptions = { position: 'bottomright' };
constructor() { }
ngOnInit() { }
onMapReady(map: L.Map) {
console.log(map);
}
}
Informaion:
- Google Chrome Version: 62.0.3202.94
- Angular-CLI Version: 1.5.0
- Angular Version: 5.0.5
- Angular Material Version: 5.0.0-rc.2
- @asymmetrik/ngx-leaflet Version: 2.5.1
Thanks in advance for your help.
About this issue
- Original URL
- State: closed
- Created 7 years ago
- Comments: 19 (2 by maintainers)
Okay, after a bit try and error I was able to find out that the following code doesn’t solve the issue:
But changing it to the following will solve the issue (even if the time is set to zero):
Thanks for giving me some hints.
@mybluedog24 In your original approach (using *ngIf), you’re running into the issue where you can’t reuse tile layers between instances of a map. You create the tile layers in
mapOptions, but I bet you aren’t recreating them when the map is recreated when *ngIf evaluates to true. This is a slightly frustrating feature of Leaflet. When layers are added to the map, they are changed by the map. If you try to reuse those layers again, they just won’t work. One way to fix this is to create a wrapper component for the map that just contains the default map options and maybe input/output bindings for the marker you’re putting on the map and whatever interactions you want to allow. Then, you could put the *ngIf on that component. When *ngIf evaluates to true, your map wrapper component is created and the map is created (and so you end up with new instances of the layers). When *ngIf evaluates to false, both the wrapper and the map itself are destroyed, ensuring that the next time it’s created, it will be completely recreated with new layers and everything.If you want to save state between viewModes (e.g., zoom/pan), you’d probably be better off using the
[hide]approach in your second example. Here, you just need to move yourinvalidateSizecall into logic that is triggered by the change in state forviewMode.(leafletMapReady)is only invoked when the map is created.[hide]doesn’t create or destroy the map, it just changes the CSS on the map DIV so that it’s hidden. But, it’s still in the DOM.(leafletMapReady)would only get invoked if you removed the map directive from the DOM using *ngIf as in your first example.Hope this helps.
Hi @d-koppenhagen, do you mind also showing how your selector is used? This issue is not specific to ngx-leaflet. Without looking at more code I can tell you some common pitfalls:
Using CSS rules for width and height with percentage (%) values. This normally doesn’t cause problems unless the ngx-leaflet directive is on an element that has not had its width/height explicitly set. You could try using viewport-percentage units (
vhorvw) which can be read about here.Using
ngIfor CSS ruledisplay: none. Both of these turn your Angular component into a 0 size element. After anngIfis true ordisplay:noneis reversed, your problem may be solved by having the leaflet map callinvalidateSizeafter one of those events happen.If neither of these suggestions are applicable, try adding a
setTimeoutcall that then has the leaflet map callinvalidateSize.Hopefully that helps, if not, please feel free to add more detail.
PS: I did not see an attached picture.
I just ran into the same issue. The problem with the timeout solutions posted above is that they will not work on very slow devices because you might run into a race condition.
The problem occurs for me when I put the leaflet directive into a custom element of my own. The issue seems to be that the parent container has a size of 0 for a few milliseconds when the map get’s initialized. You can see this here (0ms and 500ms): https://i.imgur.com/9DMijJH.png
The solution I came up with seems to work 100% of the time and on all devices no matter how slow:
@reblace Thank you so much! You saved me! Thank you for pointing out that using
[hidden]for saving state between viewModes. I’m using the[hidden]approach. Passing the map variable by(leafletMapReady)and calledinvalidateSize()after switch to map view. Here’s my code: HTML:ts:
Another thing you can do is to use an
*ngIf="show"directive and after the view init, set it on true. That worked for me. I guess the problem is when the map is loaded, so if you wait until the component is fully loaded, it’ll work properly.Hi, I have the same issue and d-koppenhagen’s solution (with or without
setTimeout) doesn’t work (I tried differnt timeout value).I’m using it in Ionic and here is my code: HTML:
ts:
Here’s the walkthrough: at the beginning the map will not show up until I change the
wiewMode:When I first time click the
Mapbutton, the map displays correctly.But after I change it to List and change back to Map view, the tile layer can’t display.
Also I tried use
[hidden]="viewMode !=='map'"but it shows like this, unless I resize the window:I’m thinking maybe is because invalidateSize() doesn’t work?
Thanks for your help!
I was facing a situation where the tiles wouldn’t re-render after routing away from the map host component and back again. The markers were visible, but no base layer.
My base layer (ESRI Satellite) would return if I refreshed the page or toggled an Open Street Map overlay on and then off again.
I fixed this using the following:
I could use a mapReady flag in combination with *ngIf, but it’s working fine without it.
I hope this helps someone else as it has taken me a few hours to work this one out. I tried invalidateSize and this didn’t work; with or without a setTimeout. Without looking into it too much, I thought this might get the map to redraw and bring the tiles back, but it didn’t work.
Here’s some code snippets which should be easy enough to follow:
template
component