Closed gharibi closed 7 years ago
It looks like everything is working correctly and the map is rendering, but you haven't loaded any layers so you're just getting an empty map.
Try updating your template to:
<div leaflet style="height: 300px;"
[leafletBaseLayers]="baseLayers"
[leafletCenter]="center"
[leafletFitBounds]="fitBounds">
</div>
And your component to:
import { Component, OnInit } from '@angular/core';
import { GlobalService } from '../shared-service/global.service';
@Component({
selector: 'app-leaflet',
templateUrl: './leaflet.component.html',
styleUrls: ['./leaflet.component.css']
})
export class LeafletComponent implements OnInit {
zoom: number;
center: L.LatLng;
fitBounds: L.LatLngBounds;
baseLayers: [ L.tileLayer( 'http://{s}.tile.opencyclemap.org/cycle/{z}/{x}/{y}.png', { maxZoom: 18 }) ];
constructor() {}
ngOnInit() {}
}
After updating the component, I get the following error on the below line of code:
baseLayers: [ L.tileLayer( 'http://{s}.tile.opencyclemap.org/cycle/{z}/{x}/{y}.png', { maxZoom: 18 }) ];
[ts] Namespace L has no exported member tileLayer
Make sure you've installed the Leaflet types @types/leaflet
and you've imported the L namespace:
import * as L from 'leaflet';
@types/leaflet
is already installed (v1.0.61). I also imported the namespace to the map component. I still get the same error that [ts] Namespace L has no exported member tileLayer
:
import { Component, OnInit } from '@angular/core';
import { GlobalService } from '../shared-service/global.service';
import * as L from 'leaflet';
@Component({
selector: 'app-leaflet',
templateUrl: './leaflet.component.html',
styleUrls: ['./leaflet.component.css']
})
export class LeafletComponent implements OnInit {
zoom: number;
center: L.LatLng;
fitBounds: L.LatLngBounds;
baseLayers: [ L.tileLayer( 'http://{s}.tile.opencyclemap.org/cycle/{z}/{x}/{y}.png', { maxZoom: 18 }) ];
constructor() {}
ngOnInit() {}
`}``
Hmm.. Something weird is going on with the Typescript compiler. I wonder if it's cause we're invoking the factory method in the class definition.
Try doing something like this (note I moved the baseLayers creation into the constructor):
import { Component, OnInit } from '@angular/core';
import { GlobalService } from '../shared-service/global.service';
import * as L from 'leaflet';
@Component({
selector: 'app-leaflet',
templateUrl: './leaflet.component.html',
styleUrls: ['./leaflet.component.css']
})
export class LeafletComponent implements OnInit {
zoom: number;
center: L.LatLng;
fitBounds: L.LatLngBounds;
baseLayers: L.TileLayer[];
constructor() {
this.baseLayers = [ L.tileLayer( 'http://{s}.tile.opencyclemap.org/cycle/{z}/{x}/{y}.png', { maxZoom: 18 }) ];
}
ngOnInit() {}
}
By invoking the factory method in the constructor, this issue is resolved but we introduce another issue.
In this case, map cannot access the DOM
element by using mapid
:
1) leaflet.component.ts (I have added the map in the constructor)
import { Component, OnInit } from '@angular/core';
import { GlobalService } from '../shared-service/global.service';
import * as L from 'leaflet';
@Component({
selector: 'app-leaflet',
templateUrl: './leaflet.component.html',
styleUrls: ['./leaflet.component.css']
})
export class LeafletComponent implements OnInit {
zoom: number;
center: L.LatLng;
fitBounds: L.LatLngBounds;
baseLayers: L.TileLayer[];
constructor() {
var sampleMap = L.map('mapid').setView([0, 0], 13);
this.baseLayers = [ L.tileLayer( 'http://{s}.tile.opencyclemap.org/cycle/{z}/{x}/{y}.png', { maxZoom: 18 }) ];
}
ngOnInit() {}
}
2) leaflet.component.html (please note at the id which I have added)
<div id="mapid" leaflet style="height: 300px;"
[leafletBaseLayers]="baseLayers"
[leafletCenter]="center"
[leafletFitBounds]="fitBounds">
</div>
3) leaflet.component.css
#mapid { height: 180px; }
**4) angular-cli.json**
"styles": [
"styles.css",
"../node_modules/leaflet/dist/leaflet.css"
]
5) package.json
`"@asymmetrik/angular2-leaflet": "^2.1.5",`
`"@types/leaflet": "^1.0.61",`
`"leaflet": "^1.0.3",`
After compiling the app, in the console, I get the below error (BTW I am using IE v11.0.9600.18665):
ERROR Error: Uncaught (in promise): Error: Map container not found.
Error: Map container not found.
P.S. Even if in leaflet.component.html
we just keep <div id='mapid'></div>
, we get the same error.
Here's a working example I made using Angular-CLI. In retrospect, I'm not sure why you were having typings issues, you should be able to inline create the base layers in the component definition.
package.json:
{
"name": "my-test",
"version": "0.0.0",
"license": "MIT",
"scripts": {
"ng": "ng",
"start": "ng serve",
"build": "ng build",
"test": "ng test",
"lint": "ng lint",
"e2e": "ng e2e"
},
"private": true,
"dependencies": {
"@angular/common": "^4.0.0",
"@angular/compiler": "^4.0.0",
"@angular/core": "^4.0.0",
"@angular/forms": "^4.0.0",
"@angular/http": "^4.0.0",
"@angular/platform-browser": "^4.0.0",
"@angular/platform-browser-dynamic": "^4.0.0",
"@angular/router": "^4.0.0",
"@asymmetrik/angular2-leaflet": "^2.1.5",
"@types/leaflet": "^1.0.61",
"core-js": "^2.4.1",
"leaflet": "^1.0.3",
"rxjs": "^5.1.0",
"zone.js": "^0.8.4"
},
"devDependencies": {
"@angular/cli": "1.0.0",
"@angular/compiler-cli": "^4.0.0",
"@types/jasmine": "2.5.38",
"@types/node": "~6.0.60",
"codelyzer": "~2.0.0",
"jasmine-core": "~2.5.2",
"jasmine-spec-reporter": "~3.2.0",
"karma": "~1.4.1",
"karma-chrome-launcher": "~2.0.0",
"karma-cli": "~1.0.1",
"karma-coverage-istanbul-reporter": "^0.2.0",
"karma-jasmine": "~1.1.0",
"karma-jasmine-html-reporter": "^0.2.2",
"protractor": "~5.1.0",
"ts-node": "~2.0.0",
"tslint": "~4.5.0",
"typescript": "~2.2.0"
}
}
angular-cli.json:
{
"$schema": "./node_modules/@angular/cli/lib/config/schema.json",
"project": {
"name": "my-test"
},
"apps": [
{
"root": "src",
"outDir": "dist",
"assets": [
"assets",
"favicon.ico"
],
"index": "index.html",
"main": "main.ts",
"polyfills": "polyfills.ts",
"test": "test.ts",
"tsconfig": "tsconfig.app.json",
"testTsconfig": "tsconfig.spec.json",
"prefix": "app",
"styles": [
"styles.css",
"../node_modules/leaflet/dist/leaflet.css"
],
"scripts": [],
"environmentSource": "environments/environment.ts",
"environments": {
"dev": "environments/environment.ts",
"prod": "environments/environment.prod.ts"
}
}
],
"e2e": {
"protractor": {
"config": "./protractor.conf.js"
}
},
"lint": [
{
"project": "src/tsconfig.app.json"
},
{
"project": "src/tsconfig.spec.json"
},
{
"project": "e2e/tsconfig.e2e.json"
}
],
"test": {
"karma": {
"config": "./karma.conf.js"
}
},
"defaults": {
"styleExt": "css",
"component": {}
}
}
app.component.html:
<div leaflet style="height: 300px;"
[leafletCenter]="center"
[leafletFitBounds]="fitBounds"
[leafletBaseLayers]="baseLayers">
</div>
app.component.ts:
import { Component } from '@angular/core';
import * as L from 'leaflet';
@Component({
selector: 'app-root',
templateUrl: './app.component.html',
styleUrls: ['./app.component.css']
})
export class AppComponent {
baseLayers = [ L.tileLayer('http://{s}.tile.openstreetmap.org/{z}/{x}/{y}.png', { maxZoom: 18 }) ];
center = L.latLng([ 46.879966, -121.726909 ]);
fitBounds = L.latLngBounds([ [40.712, -74.227], [40.774, -74.125] ]);
}
app.module.ts:
import { BrowserModule } from '@angular/platform-browser';
import { NgModule } from '@angular/core';
import { FormsModule } from '@angular/forms';
import { HttpModule } from '@angular/http';
import { LeafletModule } from '@asymmetrik/angular2-leaflet';
import { AppComponent } from './app.component';
@NgModule({
declarations: [
AppComponent
],
imports: [
BrowserModule,
FormsModule,
HttpModule,
LeafletModule.forRoot()
],
providers: [],
bootstrap: [AppComponent]
})
export class AppModule { }
@reblace thanks Ryan. I created a new cli project and used your contents. Everything works perfectly fine. I was comparing the package from your project with my project and I actually don't see difference of any version. However I have got like 100 packages. I will dig more into the issue and as soon as I figure out what the problem is, I will let you know.
Also, it would be great if you add an example section under the documentation. If you like, you can assign in to me. I can create various examples and add as a new section in the documentation.
Here's some notes on the changes:
your example:
import { Component, OnInit } from '@angular/core';
import { GlobalService } from '../shared-service/global.service';
import * as L from 'leaflet';
@Component({
selector: 'app-leaflet',
templateUrl: './leaflet.component.html',
styleUrls: ['./leaflet.component.css']
})
export class LeafletComponent implements OnInit {
zoom: number; // See note #1
center: L.LatLng; // See note #1
fitBounds: L.LatLngBounds; // See note #1
baseLayers: L.TileLayer[];
constructor() {
var sampleMap = L.map('mapid').setView([0, 0], 13); // See note #2
this.baseLayers = [ L.tileLayer( 'http://{s}.tile.opencyclemap.org/cycle/{z}/{x}/{y}.png', { maxZoom: 18 }) ]; // See note #3
}
}
my example:
import { Component } from '@angular/core';
import * as L from 'leaflet';
@Component({
selector: 'app-root',
templateUrl: './app.component.html',
styleUrls: ['./app.component.css']
})
export class AppComponent {
baseLayers = [ L.tileLayer('http://{s}.tile.openstreetmap.org/{z}/{x}/{y}.png', { maxZoom: 18 }) ];
center = L.latLng([ 46.879966, -121.726909 ]);
fitBounds = L.latLngBounds([ [40.712, -74.227], [40.774, -74.125] ]);
}
Note #1: In my example, I ensure that fitBounds is set when the map's created. There's a note in the README that talks about making sure you set the initial zoom/center before the map is created. In this case, setting fitBounds is adequate if you don't want to also set center/zoom. If the map is created without the center/zoom or fitBounds set, you'll just get a blank map that doesn't work.
Note #2: This is the big change. The angular2-leaflet directive is creating the map so you don't have to. When you call L.map('mapid').setView([0, 0], 13);
, you're actually trying to manually create a second map on that same DIV, which probably won't work (and certainly isn't what you intend). Also, there's a chance in this case that since you're trying to create the map in the constructor (as opposed to in ngOnInit) that the DOM isn't ready, which causes the operation to fail.
Note #3: You can move this back into the class definition. I think this was not actually an issue initially.
Re Examples: The demo application is supposed to provide examples. If you clone the repo, and install the deps, you should be able to run the demo and manipulate it from there. The demo uses Webpack, so while it isn't exactly compatible with Angular-CLI, it's very close. If we're going to add examples in more of a structured documentation style, I'll have to do a little research to see what the best way is to set it up.
Regarding your note no. 1: looking at other map frameworks like ArcGIS JavaScript API, even if you don't specify the extent and zoom level, you will get the map anyway. In that case the initial extent would be fullExtent of the world basemap. In our case, specifying the center/zoom we get blank map, even though we have a basemap layer already. Maybe we can add a directive and set the map to fullExtent if there is no center/zoom instead of leaving it blank.
Regarding note no. 2: I inspected the DOM element and seems like two maps get overlaid but because of some unknown reasons, the interpreter fails to process them both separately. Even if we specify different IDs, seems like we cant create a second map without using the angular2-leaflet directive. I believe this actually makes sense. In other map frameworks it is like this. The problem is. there is no documentation on the available directives. So having that documentation on angular2-leaflet directives will certainly help.
Regarding no. 3: Actually this is exactly my problem. I cant move it back to class as I get an error. As of yet, I couldn't understand why it is like this. It might be that I am conflict somewhere in my namespaces. I will look into it and update you.
Regarding the examples: If you like, in the future I can add some specific examples regarding adding WMS and WFS layers which may need some updates to the framework.
For 1, I thought a lot about establishing reasonable defaults, but in the end I tried to leave the plugin as close to Leaflet's default behavior as possible (mostly for the sake of maintainability). Leaflet doesn't apply a default zoom, center, or even base layers as there are a lot of other factors to consider like which projection is being used or whether the map is being repeated in the X/Y direction. You could bring up the idea with the Leaflet project, though.
Re 2: You can create a second map imperatively if you really want to, you just need to select a different div element and do it at the correct part of the Angular 2+ lifecycle. I extended the previous example to illustrate (see below). It's worth noting that you can't reuse layers between maps or you'll get errors. So, you actually have to create two different tileLayer objects, one for each map.
<div leaflet style="height: 300px;"
[leafletCenter]="center"
[leafletFitBounds]="fitBounds"
[leafletBaseLayers]="baseLayers">
</div>
<br/><br/>
<div id="otherMap" style="height:400px;"></div>
import { Component, OnInit } from '@angular/core';
import * as L from 'leaflet';
@Component({
selector: 'app-root',
templateUrl: './app.component.html',
styleUrls: ['./app.component.css']
})
export class AppComponent implements OnInit {
baseLayers = [ L.tileLayer('http://{s}.tile.openstreetmap.org/{z}/{x}/{y}.png', { maxZoom: 18 }) ];
center = L.latLng([ 46.879966, -121.726909 ]);
fitBounds = L.latLngBounds([ [40.712, -74.227], [40.774, -74.125] ]);
constructor() {}
ngOnInit() {
L.map('otherMap', {
layers: [ L.tileLayer('http://{s}.tile.openstreetmap.org/{z}/{x}/{y}.png', { maxZoom: 18 }) ],
center: L.latLng(46.879966, -121.726909), zoom: 12
});
}
}
Re 3: If you figure out what's going on I'd be interested to hear. There might be some conflict in your type definitions somewhere (perhaps there are other leaflet plugins that are causing issues?). I'm assuming its a compiler error, right? I can also put my example ng cli project in github tonight so you can check it out in its entirety if that might help you track down the issues.
If you have some good examples of using wms/wfs layers those would be good contributions to the demo. Feel free to add them and put in a PR. I've tested with wms, but not wfs.
Let me know if you'd like me to share the ng cli example. I really appreciate you checking out the plugin. I'm glad you can get some value out of it. Thanks!
Thanks Ryan. I will be happy to help.
For no. 1: I agree with you, it make sense to add a pull request for leaflet rather than angular2-leaflet.
For no. 2: Well done, interesting. However in real-case scenarios, users will have a lot of data on the map, therefore LazyLoading can be a solution. In this case LazyLoading will not be possible for the both maps as we cant do it for map in ngOnInt()
. Anyway, this is not a big deal, ideally users should make use of Angular2 components. This can be simply done by defining more than 1 component.
For no. 3: Finally I got what the problem is. Compare the below codes:
1)
baseLayers: [ L.tileLayer( 'http://{s}.tile.opencyclemap.org/cycle/{z}/{x}/{y}.png', { maxZoom: 18 }) ];
2)
baseLayers = [ L.tileLayer('http://{s}.tile.openstreetmap.org/{z}/{x}/{y}.png', { maxZoom: 18 }) ];
Initially, we were trying to define the variable by using :
. Therefore the compiler was looking for a type, whereas we should have assigned the baseLayer
by using =
! never mind, it happens...
Regarding the repo, since I got my project up and running now, there is no need anymore. Thank you I appreciate your assistance. I will close this request.
For the WMS/WFS examples, it would be great if you could create a pull request. Then we can discuss about this topic there.
/
Hi, I'm Parham, for fix this problem issue in Angular 6 and bootstrap Modal use this instruction.
Today fixed my problem with this instruction. To correct this problem issue should be use method this.map.invalidateSize();
in event (leafletMouseOver). Please see this sample code from here down.
/
/ // In style.css add this class map /
.map {
position: relative !important;
width: 100%; height: 600px;
margin: 2px;
padding: 2px;
}
/--------------------------------------------------------------------/
// In Angular component .ts file
import { Component, EventEmitter, OnInit, Output } from '@angular/core'; import * as L from 'leaflet';
@Component({
selector: 'app-map-control',
template:
<div class="map" leaflet (leafletMapReady)="onMapReady($event)" [leafletOptions]="options" (leafletMouseOver)="refreshMap()" style="border: black solid 1px;"> </div>
})
export class MapControlComponent {
constructor() { }
public map: L.Map = null; private latoLong: L.LatLngTuple = [35.706000, 51.4025000]; // for set static lat-long to map
// Define our base layers so we can reference them multiple times streetMaps = L.tileLayer('https://{s}.tile.openstreetmap.org/{z}/{x}/{y}.png', { detectRetina: true, attribution: '© OpenStreetMap contributors' });
// Set the initial set of displayed layers (we could also use the leafletLayers input binding for this) options = { layers: [this.streetMaps], zoom: 17, center: L.latLng(this.latoLong) };
@Output() outputLatLong = new EventEmitter<L.LatLngTuple>();
refreshMap() { if (this.map) { // this.streetMaps.redraw(); this.map.invalidateSize(); } }
onMapReady(map: L.Map) { map.on('click', (eventMouse: L.LeafletMouseEvent) => { this.latoLong = [eventMouse.latlng.lat, eventMouse.latlng.lng]; map.setView(this.latoLong, map.getZoom()); this.outputLatLong.emit(this.latoLong); }); this.map = map; }
}
I got the same issue and was solved with the comment here https://github.com/Asymmetrik/ngx-leaflet/issues/104#issuecomment-349086565
The this.map.invalidateSize();
seems to be always the solution, it's just about when to call it. For me calling in in timeout in onMapReady
solves the issue.
onMapReady(map: L.Map) {
setTimeout(() => {
map.invalidateSize();
}, 0);
}
I have used Angular Cli to generate a new project. I have also used quite a few node_modules for my application such as angularfire2, bootstrap, jQuery.
I tried to add leaflet according to the documentation, but unfortunately I don't get the map rendered:
In my project, I have created a folder in src/app called 'map' and have created a module under that called 'leaflet'. In my
leaflet.component.ts
, I have the below codes:import { Component, OnInit } from '@angular/core';
import { GlobalService } from '../shared-service/global.service';
@Component({
selector: 'app-leaflet',
templateUrl: './leaflet.component.html',
styleUrls: ['./leaflet.component.css']
})
export class LeafletComponent implements OnInit {
zoom: number;
center: L.LatLng;
fitBounds: L.LatLngBounds;
constructor() {
}
ngOnInit() {
}
}
In theleaflet.component.html
, I have the below code:<div leaflet style="height: 300px;"
[leafletCenter]="center"
[leafletFitBounds]="fitBounds">
</div>
Also in my
app.module.ts
, I have imported theLeafletModule
.Am I missing something?