angularbootstrap-modalviewchildbootstrap-carouselangular-cli-v11

@ViewChild returns undefined. I can not access to the carousel ElementRef inside a modal


I am new to Angular CLI and I am using v11. I am trying to create an image gallery that clicking on some image generates a modal with a carousel showing the selected image at the beginning. But when I click on the image and the modal appears, for some reason the @ViewChild decorator, it always returns undefined.

My template code is the following:

<mat-card>
  <mat-card-subtitle>Gallery</mat-card-subtitle>
  <mat-card-content>
    <ng-template id="mySlides" #myModal class="h-100 h-auto" let-d="dismiss">
      <div class="modal-header">
        <h4 class="modal-title">Gallery</h4>
        <button type="button" class="close mt-1" aria-label="Close" (click)="d('Cross click')">
          <span aria-hidden="true">&times;</span>
        </button>
      </div>
      <div class="modal-content">
        <ngb-carousel #myCarousel>
          <ng-template ngbSlide *ngFor="let img of images" id="{{img.id}}">
            <div class="picsum-img-wrapper">
              <img src="{{img.url}}" alt="Image {{img.id}}">
            </div>
          </ng-template>
        </ngb-carousel>
      </div>
    </ng-template>
    <div class="row text-center text-lg-left">
      <div class="col-lg-3 col-md-4 col-6" *ngFor="let img of images">
        <a style="cursor: pointer" class="d-block mb-4 h-100"
           (click)="openModal(myModal); setSlideId(img.id);navigateToSlide(img.id)">
          <img class="img-fluid img-thumbnail" src="{{img.url}}" alt="">
        </a>
      </div>
    </div>
  </mat-card-content>
</mat-card>

My ts code is the following:

import {Component, ViewChild} from '@angular/core';
import {NgbCarousel, NgbCarouselConfig, NgbModal} from '@ng-bootstrap/ng-bootstrap';


@Component({
  selector: 'kt-image-gallery-thumbnail',
  templateUrl: './image-gallery-thumbnail.component.html',
  styleUrls: ['./image-gallery-thumbnail.component.scss'],
  providers: [NgbCarouselConfig]

})

export class ImageGalleryThumbnailComponent {

  selectedSlide = 1;

  constructor(private modalService: NgbModal) {
  }

  images = [{
    id: 1,
    url: '../../../../assets/media/products/product1.jpg'
  }, {
    id: 2,
    url: '../../../../assets/media/products/product12.jpg'
  }, {
    id: 3,
    url: '../../../../assets/media/products/product11.jpg'
  }];

  @ViewChild('myCarousel', {static: false, read: NgbCarousel}) myCarousel: NgbCarousel;

  openModal(content: any) {
    this.modalService.open(content);
  }

  navigateToSlide(item) {
    console.log(this.myCarousel);
    try {
      this.myCarousel.select('' + item);
    } catch (e) {
      console.log(e);
    }

  }

  setSlideId(id: number) {
    console.log(id);
    this.selectedSlide = id;
  }
}

Thanks for the help.


Solution

  • I finally got it to work from Panagiotis Bougioukos' recommendation and I think it's simpler than what I had done. The solution is the next:

    1. I created a new component with the carousel and called it from the modal.

    Component Gallery-Carousel

    HTML Template

    <ngb-carousel #myCarousel [activeId]="item">
      <ng-template ngbSlide *ngFor="let img of images" id="{{img.id}}">
        <div class="picsum-img-wrapper">
          <img src="{{img.url}}" alt="Image {{img.id}}">
        </div>
      </ng-template>
    </ngb-carousel>
    

    TS Code

    import {Component, Input, ViewChild} from '@angular/core';
    import {NgbCarousel} from '@ng-bootstrap/ng-bootstrap';
    
    
    @Component({
      selector: 'kt-gallery-carousel',
      templateUrl: './gallery-carousel.component.html',
      styleUrls: ['./gallery.carousel.component.scss'],
    })
    
    export class GalleryCarouselComponent {
    
      @Input() item: string;
    
      @ViewChild('myCarousel', {static: true, read: NgbCarousel}) myCarousel: NgbCarousel;
    
      constructor() {
      }
    
      images = [{
        id: 1,
        url: '../../../../assets/media/products/product1.jpg'
      }, {
        id: 2,
        url: '../../../../assets/media/products/product12.jpg'
      }, {
        id: 3,
        url: '../../../../assets/media/products/product11.jpg'
      }];
    }
    
    1. I modified my Image Gallery component

    Component Image Gallery with Modal

    HTML Template

    <mat-card>
      <mat-card-subtitle>Gallery</mat-card-subtitle>
      <mat-card-content>
        <ng-template id="mySlides" #myModal class="h-100 h-auto" let-d="dismiss">
          <div class="modal-header">
            <h4 class="modal-title">Gallery</h4>
            <button type="button" class="close mt-1" aria-label="Close" (click)="d('Cross click')">
              <span aria-hidden="true">&times;</span>
            </button>
          </div>
          <div class="modal-content">
            <kt-gallery-carousel [item]="selectedSlide"></kt-gallery-carousel>
          </div>
        </ng-template>
        <div class="row text-center text-lg-left">
          <div class="col-lg-3 col-md-4 col-6" *ngFor="let img of images">
            <a style="cursor: pointer" class="d-block mb-4 h-100"
               (click)="openModal(myModal); setSlideId(img.id)">
              <img class="img-fluid img-thumbnail" src="{{img.url}}" alt="">
            </a>
          </div>
        </div>
      </mat-card-content>
    </mat-card>
    

    TS Code

    import {Component} from '@angular/core';
    import {NgbModal} from '@ng-bootstrap/ng-bootstrap';
    
    
    @Component({
      selector: 'kt-image-gallery-thumbnail',
      templateUrl: './image-gallery-thumbnail.component.html',
    })
    
    export class ImageGalleryThumbnailComponent {
      selectedSlide: string;
    
      constructor(private modalService: NgbModal) {
      }
    
      images = [{
        id: 1,
        url: '../../../../assets/media/products/product1.jpg'
      }, {
        id: 2,
        url: '../../../../assets/media/products/product12.jpg'
      }, {
        id: 3,
        url: '../../../../assets/media/products/product11.jpg'
      }];
    
      openModal(content: any) {
        this.modalService.open(content);
      }
    
      setSlideId(id: number) {
        this.selectedSlide = '' + id;
      }
    }