我正在使用AGM(Angular Google Maps),我想创建一组自己的自定义组件来包装AGM组件,以便在我的应用程序中高度重用。
但是,当我这样做时,标记(在此示例中)似乎不会在地图上呈现,但我没有错误。我想知道这是否与在<ng-content>
中嵌套组件有关
有人可以帮忙吗?我有一个stackblitz设置。请使用Slot
查看Angular 7 Stackblitz底部的更新。
TLDR:当我有嵌套的自定义组件时,它创建了一个ng-content
HTML元素中间人,似乎打破了agm
功能。
我的核心组成部分是vmap
@Component({
selector: "v-map",
template: `<agm-map flex [latitude]="lat" [longitude]="lng">
<ng-content></ng-content>
<!--agm-marker [latitude]="lat" [longitude]="lng"></agm-marker-->
</agm-map>`
})
export class VMapComponent {
lat: number = 51.678418;
lng: number = 7.809007;
constructor(private loader: MapsAPILoader) {
}
}
请注意,如果我在模板中的agm-marker
中进行评论,则会呈现。它只是在ng-content
内似乎不起作用。
这是v-map-plots
子组件
@Component({
selector: "v-map-plots",
template: `<agm-marker *ngFor="let plot of plots" [latitude]="plot.Latitude" [longitude]="plot.Longitude"></agm-marker>`
})
export class VMapPlotsComponent {
@Input() plots: IPlot[] = [];
constructor(@Host() private parent: VMapComponent) {
this.plots.push({ Latitude: 51.678418, Longitude: 7.809007 })
}
}
这是AGM问题还是Angular问题?这与ng-content
有关吗?有办法解决吗?
根据@ Anytoe的评论更新这里是我的用例:
<v-map>
<v-map-plots [plots]="displayPlots"></v-map-plots>
</v-map>
我的想法是,我可以制作一些可重复使用的地图组件,然后我可以在需要时在我的应用程序中重复使用。
更新2我读到了关于Slot的想法,并认为这可以帮助我,所以设置一个新的Stackblitz for Angular 7和使用插槽但也无法使这个工作
首先,我在Angular生态系统下工作,我建议你使用ng-content并探索它的所有功能。 Slot标签用于将内容投影到HTML5模板标签中,功能完全相同,但如果您使用Angular,则使用ng-content,因为它更强大,功能更多。
说,我看了你的stackblitz,它说没有MarkerManager的提供者。这意味着在创建AgmsMarkers时,不会实例化MarkerManager提供程序。
我搜索了一下,我看到你用这种方式组成组件,用v-map和v-map-plot,创建的顺序是下一个:
1- v-map
2- v-map-plots
3- agm-marker
4- agm-map
Angular首先在v-map上创建了投影内容,因此AgmMarker在AgmMap之前创建。这就是MarkerManager没有提供者的原因,因为它是由AgmMap组件创建的。
鉴于这种情况,我简单地做的就是不包装agm-map。我认为它对你要做的事情没有任何影响,因为你可以根据需要在内部组成尽可能多的组件,如下所示:
<agm-map flex [latitude]="lat" [longitude]="lng">
<v-map-plots></v-map-plots>
</agm-map>
我为你的stackblitz做了一个展示它的叉子:https://stackblitz.com/edit/angular-7-master-7jvsjr
希望这可以帮助!
正如在另一个答案中已经描述的那样,问题在于AGM库的设计使得它不能用于内容投影。当你在你的情况下使用它时,内容元素是在包装它的组件之前创建的,在这种情况下不起作用,因为首先创建agm-marker-elements
并且它们需要来自尚未创建的agm-map
组件的服务。它是在内容准备好后创建的。
我建议使用另一种解决方案,以便您保持设计。对于此解决方案,您将v-map-plots
组件更改为指令,因此它没有任何渲染。这意味着您不需要任何内容投影,而只需使用v-map-plots
组件中的@ContentChildren
装饰器获取所有v-map
指令。然后使用指令中的数据渲染agm-map
组件中的agm-markers
和v-map
。
这是这样的:
@Directive({
selector: "v-map-plots"
})
export class VMapPlotsDirective {
plots: IPlot[] = [];
constructor(@Host() @Inject(forwardRef(() => VMapComponent)) private parent: VMapComponent) {
this.plots.push({ Latitude: 51.678418, Longitude: 7.809007 })
console.log("yo", this.plots);
}
}
@Component({
selector: "v-map",
template: `<agm-map flex [latitude]="lat" [longitude]="lng">
<ng-container *ngFor="let vMapPlotsDirective of vMapPlotsDirectives">
<agm-marker *ngFor="let plot of vMapPlotsDirective.plots" [latitude]="plot.Latitude" [longitude]="plot.Longitude"></agm-marker>
</ng-container>
</agm-map>`
})
export class VMapComponent {
lat: number = 51.678418;
lng: number = 7.809007;
@ContentChildren(VMapPlotsDirective) vMapPlotsDirectives;
constructor(private loader: MapsAPILoader) {
}
}
这也是StackBlitz中的一个实现,所以你可以看到它在行动。