Git Product home page Git Product logo

Comments (12)

MurhafSousli avatar MurhafSousli commented on July 3, 2024

The example does not show all the option, but it has all boxTemplate itemTemplate imageTemplate and thumbTemplate. in they belong to the gallery config.

Could you add a reproduction? also have thought about trying v12

from ngx-gallery.

bcwhite-code avatar bcwhite-code commented on July 3, 2024

So, itemTemplate in a galleryConfig added to a lightbox gallery (by ID) should work in v11 with that option just like it did in v9.

I'll see if I can narrow it down and get more information.

from ngx-gallery.

bcwhite-code avatar bcwhite-code commented on July 3, 2024

Working through this...

The documentation says:

  • itemTemplate: Custom template that overrides any type of item template. (emphasis mine)

The code, however, has:

<ng-container *ngIf="load" [ngSwitch]="type">
  <ng-container *ngSwitchCase="Types.Image">
    <gallery-image [src]="imageData.src"
                   [alt]="imageData.alt"
                   [index]="index"
                   [loadingAttr]="config.loadingAttr"
                   [loadingIcon]="config.loadingIcon"
                   [loadingError]="config.loadingError"
                   (error)="error.emit($event)"></gallery-image>

    <div *ngIf="config.imageTemplate" class="g-template g-item-template">
      <ng-container *ngTemplateOutlet="config.imageTemplate; context: imageContext"></ng-container>
    </div>
  </ng-container>

  <gallery-video *ngSwitchCase="Types.Video"
                 [src]="videoData.src"
                 [mute]="videoData.mute"
                 [poster]="videoData.poster"
                 [controls]="videoData.controls"
                 [controlsList]="videoData.controlsList"
                 [disablePictureInPicture]="videoData.disablePictureInPicture"
                 [play]="isAutoPlay"
                 [pause]="currIndex !== index"
                 (error)="error.emit($event)"></gallery-video>

  <gallery-iframe *ngSwitchCase="Types.Youtube"
                  [src]="youtubeSrc"
                  [autoplay]="isAutoPlay"
                  [loadingAttr]="config.loadingAttr"
                  [pause]="currIndex !== index"></gallery-iframe>

  <gallery-iframe *ngSwitchCase="Types.Iframe"
                  [src]="data.src"
                  [loadingAttr]="config.loadingAttr"></gallery-iframe>

  <ng-container *ngSwitchDefault>
    <div *ngIf="config.itemTemplate" class="g-template g-item-template">
      <ng-container *ngTemplateOutlet="config.itemTemplate; context: itemContext"></ng-container>
    </div>
  </ng-container>
</ng-container>

The ngIf for config.itemTemplate is inside a switch case of ngSwitchDefault meaning that it doesn't get emitted for "any type of item template" but instead only those that are not image, video, youtube, or iframe.

That should mean that if I instead use imageTemplate then my caption overlay should appear. It fails, however, because the let-data="data" is not working. The attempt to access data.caption throws an "undefined" exception.

The images are added to the gallery with this code:

gallery.addImage({
    src:   this.urlPrefix + parts[0] + this.urlFullPostfix,
    thumb: this.urlPrefix + parts[0] + this.urlThumbPostfix,
    caption: captionString,
} as ImageItemData)

What is the new method for accessing arbitrary data fields from within a template?

from ngx-gallery.

MurhafSousli avatar MurhafSousli commented on July 3, 2024

When you use itemTemplate, you are creating your own type, so you also have to define this type when creating new items https://github.com/MurhafSousli/ngx-gallery/wiki/Custom-Templates#galleryitemdef

Therefore, you should use the gallery.ref.add not addImage

galleryRef.add({
  type: 'my-image-template',
  data: {
    src: 'IMAGE_SRC_URL',
    thumb: 'IMAGE_THUMBNAIL_URL'
    alt: 'Test'
  }
})

and in template

<div *galleryItemDef="let item; let type = type">
  <div *ngIf="type === 'my-image-template'">
    <img [src]="item.src">
  </div>
  <div *ngIf="type === 'my-video-template'">
    <video>  
      <source src="item.src">
    </video>
   </div>
</div>

from ngx-gallery.

bcwhite-code avatar bcwhite-code commented on July 3, 2024

I see.

I don't want a custom item since I'm only displaying images so I'll just use imageTemplate and addImage().

This works as expected:

<ng-template #gallerySlide>
    <span class="c-img-caption">testing</span>
</ng-template>

But this doesn't, showing nothing:

<ng-template #gallerySlide>
    <span *galleryImageDef="let item; let active=active" class="c-img-caption">testing</span>
</ng-template>

As soon as I add *galleryImageDef to any element (span, div, ng-container, etc.), that element and below are not added to the DOM. There are no console messages.

from ngx-gallery.

MurhafSousli avatar MurhafSousli commented on July 3, 2024

You don't need to wrap them with ng-template, the following is sufficient:

 <span *galleryImageDef="let item; let active=active" class="c-img-caption">testing</span>

Basically using a star before the directive name is a shortcut to produce

<ng-template>
    <span [galleryImageDef]="let item; let active=active" class="c-img-caption">testing</span>
</ng-template>

When querying with ViewChild just use the directive class

@ViewChild(GalleryImageDef) imageDef: GalleryImageDef;

from ngx-gallery.

bcwhite-code avatar bcwhite-code commented on July 3, 2024

In my component's template, I tried:

...
<span *galleryImageDef="let item; let active=active" class="c-img-caption">testing</span>
...

but

@ViewChild(GalleryImageDef) imageDef: GalleryImageDef;

results in undefined. Even if it had been found, I can't assign that to imageTemplate in setConfig() because the types don't match: Type  GalleryImageDef  is missing the following properties from type  TemplateRef :  elementRef, createEmbeddedView

I tried the "expanded" version with [galleryImageDef] but that is an error: Property galleryImageDef is not provided by any applicable directives nor by span element

For reference, here is my entire component:

import {AfterViewInit, Component, Input, OnChanges, SimpleChanges, TemplateRef, ViewChild} from '@angular/core';
import {CommonModule} from "@angular/common";
import {Gallery, GalleryState, ImageItemData} from "ng-gallery";
import {Lightbox} from "ng-gallery/lightbox";
import {MatIconModule} from "@angular/material/icon";
import {MatTooltipModule} from "@angular/material/tooltip";

import {AppConstants} from "../AppConstants";
import {ImageThumbnailStripComponent} from "./image-thumbnail-strip/image-thumbnail-strip.component";

const GALLERY_ID = "thumbstrip-gallery"

@Component({
    standalone: true,
    imports: [CommonModule, ImageThumbnailStripComponent, MatIconModule, MatTooltipModule],
    selector: 'lightbox-thumbnail-strip',
    template: `
        <image-thumbnail-strip [urlPrefix]="urlPrefix" [urlPostfix]="urlThumbPostfix" [imageIds]="imageIds"
                               [orientation]="orientation">
        </image-thumbnail-strip>

        <ng-template #gallerySlide>
            <span *galleryImageDef="let item; let active=active" class="c-img-caption">testing</span>
            <!-- span *ngIf="(data.caption??'')!=''" class="c-img-caption">
                {{data.caption}}
            </span -->
        </ng-template>

        <ng-template #galleryBox>
            <div class="c-btn c-btn-share-tab" title="Send image to another tab." i18n-title>
                <mat-icon class="c-btn-icon" (click)="onShareToTabClicked($event)">open_in_browser</mat-icon>
            </div>
        </ng-template>
    `,
    styles: [`
        :host, lightbox-thumbnail-strip {
            display: block;
            height: 100%;
            width: 100%;
            cursor: pointer;
        }
        .c-img-caption {
            position: absolute;
            bottom: 20px;
            left: 50%;
            transform: translateX(-50%);
            padding: 0.4rem 1rem 0.4rem 1rem;
            background-color: antiquewhite;
            border: 1px solid black;
            color: black;
            border-radius: 1.0rem;
            font-size: 1.2rem;
            font-style: italic;
            font-weight: bold;
        }
        .c-btn {
            position: absolute;
            left: 0.9em;
            width: 2em;
            height: 2em;
            z-index: 60;
            color: white;
            opacity: 0.6;
            text-shadow: 0 0 2px rgba(0,0,0,0.8);
            transition: opacity linear 0.15s;
            cursor: pointer;
        }
        .c-btn-icon {
            width: 2em;
            height: 2em;
            font-size: 2em;
        }
        .c-btn:hover {
            opacity: 1;
        }
        .c-btn-share-tab {
            top: 0.9em;
            left: 0.9em;
        }
        .c-btn-share-pv {
            top: 3.9em;
            left: 0.9em;
        }
    `]
})
export class LightboxThumbnailStripComponent implements AfterViewInit, OnChanges {
    @Input() urlPrefix: string = ''
    @Input() urlFullPostfix: string = ''
    @Input() urlThumbPostfix: string = ''
    @Input() imageTags: string[] = []
    @Input() orientation: 'h'|'v' = 'h'

    @ViewChild(ImageThumbnailStripComponent) thumbnailStrip!: ImageThumbnailStripComponent
    @ViewChild('gallerySlide') gallerySlide!: TemplateRef<any>
    @ViewChild('galleryBox')   galleryBox!:   TemplateRef<any>

    imageIds: string[] = []
    currentIndex: number = 0

    constructor(private gallery: Gallery, private lightbox: Lightbox) {
    }

    ngAfterViewInit(): void {
        this.thumbnailStrip.clicked$.subscribe((id: string) => {
            this.openLightbox(id)
        })
        this.gallery.ref(GALLERY_ID).indexChanged.subscribe((state: GalleryState) => {
            this.currentIndex = state.currIndex || 0
        })
    }

    ngOnChanges(changes: SimpleChanges) {
        this.imageIds = this.imageTags.map(tag => tag.split(':', 1)[0])
    }

    openLightbox(id: string) {
        const gallery = this.gallery.ref(GALLERY_ID)
        gallery.reset()
        gallery.setConfig({
            imageTemplate: this.gallerySlide,
            boxTemplate: this.galleryBox,
            thumb: this.imageTags.length > 1,

            loadingStrategy: "lazy",
            slidingDirection: "horizontal",
            loop: false,
            counterPosition: "top",
            nav: true,
            dots: false,
            autoPlay: false,
        })
        this.lightbox.setConfig({
            hasBackdrop: true,
            keyboardShortcuts: true,
            panelClass: 'fullscreen',
        })
        for (let tag of this.imageTags) {
            let parts = tag.split(':')
            if (parts.length == 1) parts[1] = parts.slice(1).join(':')
            gallery.addImage({
                src:   this.urlPrefix + parts[0] + this.urlFullPostfix,
                thumb: this.urlPrefix + parts[0] + this.urlThumbPostfix,
                caption: (parts.length > 1) ? parts[1] : '',
            } as ImageItemData)
        }

        for (let i = 0; i < this.imageIds.length; i++) {
            if (this.imageIds[i].startsWith(id)) {
                this.currentIndex = i
                this.lightbox.open(i, GALLERY_ID)
                break
            }
        }
    }

    onShareToTabClicked($event: MouseEvent) {
        let parts = this.imageTags[this.currentIndex].split(':')
        if (parts.length == 1) parts[1] = parts.slice(1).join(':')
        window.open(`${AppConstants.SHOW_PAGE}?b=${parts[0]+this.urlFullPostfix}&c=${encodeURIComponent(parts[1])}`, 'dimg')
    }
}

from ngx-gallery.

bcwhite-code avatar bcwhite-code commented on July 3, 2024

Ahhh... This works:

<ng-template #gallerySlide let-data>
    <span class="c-img-caption" *ngIf="(data.caption??'')!=''">{{data.caption}}</span>
</ng-template>

from ngx-gallery.

MurhafSousli avatar MurhafSousli commented on July 3, 2024

Ofcourse, this code will not work

<ng-template  #gallerySlide>
  <span *galleryImageDef="let item; let active=active" class="c-img-caption">testing</span>
</ng-template>

Because wrapping content with ng-template means it will not be rendered, therefore @ViewChild will return undefined

This is how you should use it

@Component({
    standalone: true,
    imports: [GalleryModule, CommonModule, ImageThumbnailStripComponent, MatIconModule, MatTooltipModule],
    selector: 'lightbox-thumbnail-strip',
    template: `
        <image-thumbnail-strip [urlPrefix]="urlPrefix" [urlPostfix]="urlThumbPostfix" [imageIds]="imageIds"
                               [orientation]="orientation">
        </image-thumbnail-strip>

       <span *galleryImageDef="let item; let active=active" class="c-img-caption">testing</span>

        <div *galleryBoxDef class="c-btn c-btn-share-tab" title="Send image to another tab." i18n-title>
                <mat-icon class="c-btn-icon" (click)="onShareToTabClicked($event)">open_in_browser</mat-icon>
        </div>
    `,
})
export class LightboxThumbnailStripComponent implements AfterViewInit, OnChanges {
  
    @ViewChild(GalleryImageDef) imageDef: GalleryImageDef;

    @ViewChild(GalleryBoxDef) galleryBox: GalleryBoxDef;

    ngAfterViewInit(): void {
        this.thumbnailStrip.clicked$.subscribe((id: string) => {
            this.openLightbox(id)
        })

        // Set the config here, you can use setConfig or inside ref function
        this.gallery.ref(GALLERY_ID, {
            imageTemplate: this.imageDef.templateRef,
            boxTemplate: this.galleryBox.templateRef,
            loadingStrategy: "lazy",
            slidingDirection: "horizontal",
            loop: false,
            counterPosition: "top",
            nav: true,
            dots: false,
            autoPlay: false,
        }).indexChanged.subscribe((state: GalleryState) => {
            this.currentIndex = state.currIndex || 0
        })
    }

    openLightbox(id: string) {
        const gallery = this.gallery.ref(GALLERY_ID)
        gallery.reset()
       // Not sure if you need to do it here but you can update the config at any time
        gallery.setConfig({
            thumb: this.imageTags.length > 1,
        })
        this.lightbox.setConfig({
            hasBackdrop: true,
            keyboardShortcuts: true,
            panelClass: 'fullscreen',
        })
       // .....
   }
}

Don't forget to import GalleryModule or its directives individually in the component's imports

from ngx-gallery.

bcwhite-code avatar bcwhite-code commented on July 3, 2024

As I said, I tried just

<span *galleryImageDef="let item; let active=active" class="c-img-caption">testing</span>

(no surrounding ) and it wasn't found. Maybe because there was some import missing but there were no build errors. In addition, I could not pass a variable of the form

@ViewChild(GalleryImageDef) imageDef: GalleryImageDef;

to imageTemplate because of a type mismatch.

But it does work with just

<ng-template #gallerySlide let-data>
    <span class="c-img-caption" *ngIf="(data.caption??'')!=''">{{data.caption}}</span>
</ng-template>

from ngx-gallery.

MurhafSousli avatar MurhafSousli commented on July 3, 2024

I just tried it on my end, it works... They all have the same type when you pass the imageDef.templateRef, maybe you are passing just imageDef and thus you get type mismatch

If you provide a reproduction stackblitz I can help with it, but if you are good with ng-template then we can close this I guess

from ngx-gallery.

bcwhite-code avatar bcwhite-code commented on July 3, 2024

imageDef.templateRef would be the difference.

Thanks for all your help!

from ngx-gallery.

Related Issues (20)

Recommend Projects

  • React photo React

    A declarative, efficient, and flexible JavaScript library for building user interfaces.

  • Vue.js photo Vue.js

    🖖 Vue.js is a progressive, incrementally-adoptable JavaScript framework for building UI on the web.

  • Typescript photo Typescript

    TypeScript is a superset of JavaScript that compiles to clean JavaScript output.

  • TensorFlow photo TensorFlow

    An Open Source Machine Learning Framework for Everyone

  • Django photo Django

    The Web framework for perfectionists with deadlines.

  • D3 photo D3

    Bring data to life with SVG, Canvas and HTML. 📊📈🎉

Recommend Topics

  • javascript

    JavaScript (JS) is a lightweight interpreted programming language with first-class functions.

  • web

    Some thing interesting about web. New door for the world.

  • server

    A server is a program made to process requests and deliver data to clients.

  • Machine learning

    Machine learning is a way of modeling and interpreting data that allows a piece of software to respond intelligently.

  • Game

    Some thing interesting about game, make everyone happy.

Recommend Org

  • Facebook photo Facebook

    We are working to build community through open source technology. NB: members must have two-factor auth.

  • Microsoft photo Microsoft

    Open source projects and samples from Microsoft.

  • Google photo Google

    Google ❤️ Open Source for everyone.

  • D3 photo D3

    Data-Driven Documents codes.