ngx-mapbox-gl
ngx-mapbox-gl copied to clipboard
Ng content not working
base-map.html
<mgl-map #map[style]="'mapbox://styles/mapbox/streets-v9'" [zoom]="[2]" [center]="[-103.59179687498357, 40.66995747013945]" (click)="onMapClick($event, map)"
(load)="mapLoad($event)" (mouseMove)="onMapMouseMove($event, map)" [cursorStyle]="cursorStyle">
<ng-content > </ng-content>
<mgl-control mglGeocoder position="top-right"></mgl-control>
</mgl-map>
base-map.ts
import { Component, } from '@angular/core';
import { MapMouseEvent } from 'mapbox-gl';
@Component({
selector: 'base-map',
templateUrl: 'base-map.component.html',
})
export class BaseMapComponent implements OnChanges {
mapLoad() { }
onMapClick(evt: MapMouseEvent) {
console.log(evt);
}
onMapMouseMove(evt: MapMouseEvent) {
console.log(evt);
}
}
point-map.html
<mgl-geojson-source id="mainSrc_cluster" [data]="mapGeoJSON" [cluster]="isCluster" [clusterMaxZoom]="14" [clusterRadius]="50">
</mgl-geojson-source>
<mgl-layer id="clusters" type="circle" source="mainSrc_cluster" [filter]="['has', 'point_count']" [paint]="{
'circle-color': {
property: 'point_count',
type: 'interval',
stops: [
[0, '#51bbd6'],
[100, '#f1f075'],
[750, '#f28cb1']
]
},
'circle-radius': {
property: 'point_count',
type: 'interval',
stops: [
[0, 20],
[100, 30],
[750, 40]
]
}
}">
</mgl-layer>
<mgl-layer id="cluster-count" type="symbol" source="mainSrc_cluster" [filter]="['has', 'point_count']" [layout]="{
'text-field': '{point_count}',
'text-font': ['DIN Offc Pro Medium', 'Arial Unicode MS Bold'],
'text-size': 12
}">
</mgl-layer>
<mgl-layer id="unclustered-point" type="circle" source="mainSrc_cluster" (click)="onClick($event)" (mouseEnter)="cursorStyle = popupList.length > 0 || pointPopupHeader ? 'pointer' : ''"
(mouseLeave)="cursorStyle = ''" [filter]="['!has', 'point_count']" [paint]="{
'circle-color': unClusterPointColor,
'circle-radius': [
'interpolate', ['linear'], ['zoom'],
10, 5,
22, 20
],
'circle-stroke-width': 1,
'circle-stroke-color': '#fff'
}">
</mgl-layer>
similary i have file for lines.map.html, and have other files, containing layers and event handlers on that layer.
now in the main app file main-app.ts
<base-map #map>
<point-map [mapData]="mapData" [mapMetaData]="mapMetaData"
[mapComponent]="map.mapComp"
></point-map>
</base-map>
the problem with approach is that im getting error ERROR Error: StaticInjectorError(AppModule)[LayerComponent -> MapService]:
also the element projected inside ng-content is called first in angular intitalization. so layer, and geojson component is initialzed before mgl-map component
StaticInjectorError is solved by adding MapService in app.module(myApp) provider.
I have one more issue of: Due to ng-content GeoJSONSourceComponent ngOnInit is called before MapComponent ngOnInit (angular lifecycle method)
private hookEvents(events: MapEvent) {
this.mapInstance.on('load', () => {
this.mapLoaded.next(undefined);
ngOnInit() {
this.MapService.mapLoaded$.subscribe(() => {
this.MapService.addSource(this.id, {
Because of that nothing is plotted on map. if (!this.sourceAdded) is always false.
But later map onLoad would is fired, and mapLoaded.next(undefined), is pushed. in GeoJsonComponent mapLoaded event is subscribed to, but that subscription is not working. If that subscription work this.sourceAdded would be true and data would be plotted on map.
You can't use ng-content in this case, because ng-content is for static content projection. To fulfill your use case, you can do dynamic content projection with ng-template. I can provide you an example if you want.
(Don't provide MapService to something else than a component, it won't work properly).
Please, provide an example
is there any possibility of integrating deck.gl in future
@Wykks Did you provide the example somewhere yet? I would be interested in an example where you add the mapbox-gl-draw control to the map.
@Wykks example ?
@Wykks I have attempted to use dynamic content injection but I still get the same StaticInjectorError. I am using an ng-template in my parent component and injecting it using ngTemplateOutlet.
May you share an example of dynamic content injection where this will work, please?
Guy, i think we need to ask it other way. Why do we need this capability at all? What use case we are trying to implement? Is there a way to implement it using existing functionality.
Please, everyone who is interested here. State your case. What exactly you are trying to achieve by injecting content into the map object?
@dmytro-gokun Here's one use case. I have 2 maps on the same page that I want to bind to the same list of sources. However, I would prefer not to duplicate the logic and instead wrap it in a template. What I'd like to do is something like this:
<mgl-map #map1 ...>
...
<ng-container [ngTemplateOutlet]="mapDataSourcesTemplate"
[ngTemplateOutletContext]="{ dataSources: dataSources$ }">
</ng-container>
...
</mgl-map>
<mgl-map #map2 ...>
...
<ng-container [ngTemplateOutlet]="mapDataSourcesTemplate"
[ngTemplateOutletContext]="{ dataSources: dataSources$ }">
</ng-container>
...
</mgl-map>
<ng-template #mapDataSourcesTemplate
let-dataSources="dataSources">
<ng-container *ngFor="let dataSource of dataSources | async">
<ng-container [ngSwitch]="dataSource.type">
<mgl-geojson-source *ngSwitchCase="'GEOJSON'"
[id]="dataSource.id"
[data]="dataSource.data"></mgl-geojson-source>
<mgl-image-source *ngSwitchCase="'IMAGE'"
[id]="dataSource.id"
[coordinates]="dataSource.coordinates"
[url]="dataSource.url"></mgl-image-source>
...
</ng-container>
</ng-container>
</ng-template>
When I do, however, I get the following error:
NullInjectorError: R3InjectorError(AppModule)[MapService -> MapService -> MapService]:
NullInjectorError: No provider for MapService!
I can get rid of this error by adding MapService
as a provider in AppModule
. However, none of the sources get added to the map likely due to what @behuda outlined above.
Any updates?
Guy, i think we need to ask it other way. Why do we need this capability at all? What use case we are trying to implement? Is there a way to implement it using existing functionality.
Please, everyone who is interested here. State your case. What exactly you are trying to achieve by injecting content into the map object?
I think it might be very useful in case you have to display many maps in your project, thanks to that approach with content projection you can reduce configuration boilerplate, ease testing and still keep the flexibility in usage.
This is tempting and makes sense only if you have 2 or more maps in your project that's probably why content projection based solution came to my mind as well :)