Вложенные угловые компоненты карт Google не отображаются

Я использую AGM (Angular Google Maps) и хочу создать набор моих собственных пользовательских компонентов, которые обертывают компоненты AGM, чтобы обеспечить многократное использование в моем приложении.

Однако, когда я это делаю, маркеры (в этом примере) не отображаются на карте, но я не получаю ошибок. Интересно, связано ли это с вложением компонентов в <ng-content>

Кто-нибудь может помочь? У меня есть настройка stackblitz. Пожалуйста, смотрите обновления внизу для Angular 7 Stackblitz, используя Slot.

TL; DR: когда у меня есть вложенные пользовательские компоненты, он создает 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. Я читал о слоте и подумал, что это может мне помочь, поэтому настройте новый Stackblitz для Angular 7 и использовал слот, но также не смог заставить это работать


person Chris    schedule 29.10.2018    source источник
comment
Для чего вы хотите использовать ng-content? Ваш пользовательский компонент работает нормально, не так ли?   -  person Anytoe    schedule 04.11.2018
comment
@Anytoe Хороший вопрос, я соответствующим образом обновил свой вопрос. Мне нужно вложить мои компоненты и сделать их шаблоны рендерингом, поэтому ng-content. Если я не использую это, графики даже не отображаются в разметке. Если есть другой способ сделать это, дайте мне знать :)   -  person Chris    schedule 05.11.2018
comment
Я поигрался с вашим stackblitz и заменил ‹! - agm-marker [latitude] = lat [longitude] = lng› ‹/agm-marker--› на ‹v-map-plots› ‹/ v-map -сюжеты ›и на« Хамме »была булавка. Разве ты не этого хочешь?   -  person Anytoe    schedule 05.11.2018
comment
@Anytoe Это эффект, я хочу поблагодарить вас. Но я хочу, чтобы v-map-plots был вложен непосредственно под v-map, а не внутри шаблона (по сути, код через app.component.html), если это имеет смысл, не стесняйтесь размещать свой stackblitz :)   -  person Chris    schedule 05.11.2018


Ответы (2)


Прежде всего, если вы работаете в экосистеме 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

Надеюсь это поможет!

person Llorenç Pujol Ferriol    schedule 21.02.2019

Как уже описано в другом ответе, проблема в том, что дизайн библиотеки 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 так что вы можете увидеть это в действии.

person AlesD    schedule 21.02.2019
comment
Таким образом «сохраняется» структура Криса, хотя ее нельзя расширить. Под этим я подразумеваю, что каждый раз, когда Крис добавляет новый компонент внутрь карты, например многоугольник, ему также придется изменять компонент v-map, чтобы поддерживать его. таким образом вы закончите с архитектурой связанных компонентов, которую я бы не рекомендовал. Фактически, цель проекции контента - избежать этого конкретного варианта использования. - person Llorenç Pujol Ferriol; 22.02.2019
comment
Да, я согласен с вами, что это не лучшее решение с архитектурной точки зрения. Просто хотел предложить альтернативное решение, сохраняющее оригинальный дизайн. - person AlesD; 23.02.2019