Skip to content

Cannot read properties of undefined (reading 'width') && undefined is not an object (evaluating 'this.containerRect.height') #1485

Closed
@felix-berlin

Description

@felix-berlin

Description

Hi, we are using lightGallery in a larger project where we use Sentry for error logging. For some time now we have been receiving thousands of errors that seem to be related to lightGallery.

Unfortunately I have not been able to reproduce these errors myself. That's the reason why I created this issue.

In the following a few stack traces from Sentry:

Cannot read properties of undefined (reading 'getBoundingClientRect')

{snip} is.core.index).find(".lg-image").first().get(),i=0,r=0,s=n.getBoundingClientRect();t?(i=n.offsetHeight*t,r=n.offsetWidth*t):e?(i=s.height+e* {snip}

Cannot read properties of undefined (reading 'width')

{snip} ,e,n,i){if(!(Math.abs(e)<=0)){var r,s,o=this.containerRect.width/2+this.containerRect.left,a=this.containerRect.height/2+this.containerRect. {snip}

undefined is not an object (evaluating 'this.containerRect.height')

{snip} t,e,n,i){if(!(Math.abs(e)<=0)){var r,s,o=this.containerRect.width/2+this.containerRect.left,a=this.containerRect.height/2+this.containerRect {snip}

In the project we use Vue 2 + Laravel and lightGallery as a normal JS bundle.

Many thanks in advance!

Steps to reproduce

Unfortunately, I can't provide a demo, even though that would be much better to understand where the error might be.

JS code that you use to initialize lightGallery.

<!-- Bild-Slider in der Lightbox -->

<template>
	<div class="m-lightbox">
		<transition name="fade-fast">
			<!-- Benachrichtigung, dass der Link der Produktdetailseite in die Zwischenablage kopiert wurde -->
			<div class="c-alert c-alert--success c-alert--success-buybox-image"
				 v-if="this.showLinkCopiedTooltip">
				{{ __('product_box.tooltips.copied') }}
			</div>
		</transition>
	</div>
</template>

<script>
import lightGallery from 'lightgallery';
import 'lightgallery/css/lightgallery.css';
import 'lightgallery/css/lg-thumbnail.css';
import 'lightgallery/css/lg-video.css';
import 'lightgallery/css/lg-zoom.css';
import lgThumbnail from 'lightgallery/plugins/thumbnail';
import lgZoom from 'lightgallery/plugins/zoom';
import lgVideo from 'lightgallery/plugins/video';

export default {
	name: 'LightboxWrapper',

	props: {
		lightGallerySelector: {
			type: String,
			default: '#vendor-light-gallery',
		},
		hasInfoText: {
			type: Boolean,
			default: false,
		},
	},

	data() {
		return {
			showLinkCopiedTooltip: false,
			lightGalleryDOMElement: null,
			currentImage: null,
		};
	},

	methods: {
		initLightGallery() {
			this.$callIfElementExists(this.lightGallerySelector, el => {
				// Docs: https://www.lightgalleryjs.com/docs/settings/
				lightGallery(el, {
					plugins: [lgThumbnail, lgZoom, lgVideo],
					thumbnail: true,
					animateThumb: false,
					showThumbByDefault: false,
					licenseKey: process.env.MIX_LIGHT_GALLERY_KEY,
					speed: 500,
					download: false, // zeige keinem Download-Icon an
					autoplayFirstVideo: false, // starte Videos nicht automatisch
					strings: {
						previousSlide: this.__('slider.prev_button'),
						nextSlide: this.__('slider.next_button'),
						closeGallery: this.__('general.close'),
						playVideo: this.__('Play video'),
					},
					mobileSettings: {
						controls: false,
						showCloseIcon: true,
					},
				});

				this.lightGalleryDOMElement = el;
				this.setUpLightGalleryEventListeners();
			});
		},

		/**
		 * Initialisiere Event Listeners für die Bilder im Gallery
		 * */
		setUpLightGalleryEventListeners() {
			// Nachdem ein Bild geladen wurde, erstelle auch einen Event-Listener fürs Bild, für das Öffnen vom Kontextmenü
			// Docs: https://www.lightgalleryjs.com/docs/events/#lgSlideItemLoad
			this.lightGalleryDOMElement.addEventListener('lgSlideItemLoad', event => {
				this.currentImage = document.querySelector(`#lg-item-1-${event.detail.index} img`);

				if (!this.currentImage) return;

				this.currentImage.addEventListener('contextmenu', this.imageEventListener);
			});

			// Bevor das Gallery geschlossen wird, bzw. bevor ein Bild gewechselt wird, entferne den Event-Listener
			// Docs: https://www.lightgalleryjs.com/docs/events/#lgBeforeSlide
			this.lightGalleryDOMElement.addEventListener('lgBeforeSlide', this.removeImageEventListener);
			// Docs: https://www.lightgalleryjs.com/docs/events/#lgBeforeClose
			this.lightGalleryDOMElement.addEventListener('lgBeforeClose', this.removeImageEventListener);
		},

		/**
		 * Die Funktion die immer auf Rechtsklick vom Bild ausgeführt wird
		 * */
		imageEventListener(e) {
			e.preventDefault();
			this.$copyProductLinkToClipBoard();
		},

		/**
		 * Cleanup-Funktion für den Event-Listener
		 * */
		removeImageEventListener() {
			if (!this.currentImage) return;

			this.currentImage.removeEventListener('contextmenu', this.imageEventListener);
			this.currentImage = null;
		},
	},

	mounted() {
		this.initLightGallery();
	},
};
</script>

Sample HTML markup

@php
	$combinedImages = array_merge([data_get($article, 'images.main')], data_get($article, 'images.additional', []));
@endphp

<!-- Bild-Slider in der Buybox auf der Artikeldetailseite -->
<div class="m-buybox__wrap-img is-loading">

	<transition name="fade-fast" v-cloak>
		<!-- Benachrichtigung, dass der Link der Produktdetailseite in die Zwischenablage kopiert wurde -->
		<div class="c-alert c-alert--success c-alert--success-buybox-image"
			 v-if="this.showLinkCopiedTooltip">
			{{ __('product_box.tooltips.copied') }}
		</div>
	</transition>

	<div class="m-buybox__slider">

		<!-- Slider main container -->
		<div class="c-slider c-slider--buybox swiper-container">
			<!-- Additional required wrapper -->
			{{-- Folgendes Markup, muss kompatibel mit Anforderungen aus lightGallery sein--}}
			{{-- Für Doku dazu, siehe: https://www.lightgalleryjs.com/docs/getting-started/#the-markup --}}
			<div class="c-slider__wrapper swiper-wrapper vendor-light-gallery" id="product-slider-wrapper">

				@foreach($combinedImages as $key => $image)
					@php
						$productImage = new \App\Helpers\ImageHelper(data_get($image, 'src'));
						$imageClasses = 'c-slider__image m-buybox__img';
						if (data_get($image, 'src') !== null) $imageClasses .= ' has-pointer';
					@endphp

					<div data-src="{{ $productImage->getImage(2400) }}"
						 class="c-slider__item swiper-slide vendor-light-gallery-item"
						 data-sub-html="{{ __('product_box.product_image_info_text') }}"
						 @dragstart.prevent="()=> false"
						 @drop.prevent="()=> false"
						 @contextmenu.prevent="$copyProductLinkToClipBoard()">

						<img
							alt="{{ __('product_slider.product_img_alt', ['number' => $key, 'product' => trim(escapeZWNJChar(data_get($article, 'standard.title'))) ]) }}"
							decoding="async"
							height="566"
							width="566"
							v-on:error="$setFallbackImage($event, '600x600')"
							class="{{ $imageClasses }}"
							src="{{ $productImage->getImage(600) }}"
							loading="{{ $key === 0 ? 'eager' : 'lazy' }}"
							fetchpriority="{{ $key === 0 ? 'high' : 'low' }}"
						>

						@if(data_get($image, 'src'))
							<span class="m-buybox__info-txt">{{ __('product_box.product_image_info_text') }}</span>
						@endif
					</div>
				@endforeach

			</div>

		</div>

		@if(count($combinedImages) > 1)
			<div class="c-slider__nav c-slider__nav--prev swiper-button-prev"
				 aria-label="{{ __('slider.prev_button') }}"
				 role="button"
				 aria-controls="product-slider-wrapper">
				<i class="c-slider__nav-icon icon icon-arrow-left"></i>
			</div>
			<div class="c-slider__nav c-slider__nav--next swiper-button-next"
				 aria-label="{{ __('slider.next_button') }}"
				 role="button"
				 aria-controls="product-slider-wrapper">
				<i class="c-slider__nav-icon icon icon-arrow-left"></i>
			</div>
		@endif

		@if(data_get($article, 'homologation.icon') && data_get($article, 'homologation.value'))
			<button type="button"
					title="{{ data_get($article, 'homologation.value') }}"
					class="m-buybox__homologation"
					@click.prevent="$modal.show('homologationModal', { homologation: '{{ data_get($article, 'homologation.value') }}' })">
				<img src="{{ data_get($article, 'homologation.icon') }}"
					 alt="{{ escapeZWNJChar(data_get($article, 'homologation.value')) }}" decoding="async"
					 loading="eager">
			</button>
		@endif

	</div>

	@if(!empty(data_get($article, 'images.additional', [])) || !empty($videos))

		<div class="m-buybox__thumbnails">
			<div class="c-slider c-slider--thumbnails swiper-thumb-container">
				<div class="c-slider__wrapper swiper-wrapper">

					@unless(empty($videos))
						<a href="#productvideo" v-anchor-scroll aria-label="{{ __('product_slider.jump_to_video') }}">
							<div class="c-slider__item swiper-slide is-video-thumbnail-slide">
								<i class="fa fa-play-circle-o"></i>
							</div>
						</a>
					@endunless

					@foreach($combinedImages as $key => $image)
						@php($productImage = new \App\Helpers\ImageHelper(data_get($image, 'src')))

						<div class="c-slider__item swiper-slide">
							<img src="{{ $productImage->getImage(155) }}"
								 loading="eager"
								 decoding="async"
								 v-on:error="$setFallbackImage($event, '155x155')"
								 alt="{{ __('product_slider.product_img_alt', ['number' => $key, 'product' => trim(escapeZWNJChar(data_get($article, 'standard.title'))) ]) }}"
								 class="m-buybox__img c-slider__image">
						</div>
					@endforeach
				</div>
			</div>

		</div>
	@endif

	<lightbox light-gallery-selector=".vendor-light-gallery"></lightbox>
</div>



Environment

  • lightGallery version: 2.7.1

Cannot read properties of undefined (reading 'height')

Bildschirm­foto 2023-03-22 um 15 27 19

Cannot read properties of undefined (reading 'width')

Bildschirm­foto 2023-03-22 um 15 24 15

Additional context

Metadata

Metadata

Assignees

No one assigned

    Labels

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions