1

我正在使用 AGM(Angular Google Maps),我想创建一组我自己的自定义组件,这些组件包装 AGM 组件以允许在我的应用程序中进行高度重用。

但是,当我这样做时,标记(在此示例中)似乎没有在地图上呈现,但我没有收到任何错误。我想知道这是否与嵌套组件有关<ng-content>

任何人都可以帮忙吗?我有一个stackblitz设置。请参阅底部的更新,了解使用Slot.

TLDR:当我嵌套自定义组件时,它会创建一个似乎破坏功能的ng-contentHTML 元素中间人。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 并认为这可以帮助我,所以为 Angular 7 设置了一个新的 Stackblitz并使用了 slot,但也无法让它工作

4

2 回答 2

1

首先,我在Angular 生态系统下工作,我建议你使用ng-content并开发它的所有功能。Slot 标签用于将内容投影到 HTML5 模板标签中,功能完全相同,但如果您在 Angular 下工作,请使用 ng-content,因为它更强大、更通用。

说,我看过你的 stackblitz,它说MarkerManager 没有提供者。这意味着在创建 AgmsMarkers 时,不会实例化 MarkerManager 提供程序。

我搜索了一下,我看到你用 v-map 和 v-map-plots 组合组件的方式,创建顺序是下一个:

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

希望这可以帮助!

于 2019-02-21T08:57:14.137 回答
0

正如其他答案中已经描述的那样,问题在于 AGM 库的设计使其不适用于内容投影。当您在您的情况下使用它时,内容元素是在包装它的组件之前创建的,这在这种情况下不起作用,因为agm-marker-elements它们是首先创建的,并且它们需要来自agm-map尚未创建的组件的服务。它是在准备好内容后创建的。

我建议使用另一种解决方案来保留您的设计。对于此解决方案,您将v-map-plots组件更改为指令,因此它没有任何渲染。这意味着您不需要任何内容​​投影,而只需使用组件内的装饰器获取所有v-map-plots指令。然后使用指令中的数据在组件中渲染和。@ContentChildrenv-mapagm-mapagm-markersv-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中的一个实现,因此您可以看到它的实际效果。

于 2019-02-21T22:15:23.870 回答