How to To Change Auto Navigation in a Modal?

KwebenaAcquah-9104 326 Reputation points
2025-03-30T01:15:04.6666667+00:00

I have a modal that previews my image products (originally i have a productgridcontainer that automatically circles through these image products for my customers to see the avilable products which i want it to be that way but i want the modal to be different. it shouldn't do what the productgridcontainer is doing... should stop cycling and let the customers use the <> right and left buttons to controll the flow) and it automatically changes these image product withing a specific subcategory image product items.... that is it circles through it and keeps changing over and over again... for my customers to see what products we have available but here lies the case i want to make it stop! so that i will use the <>right and left navigation buttons to circle throught these image products... so my customers can read and have full control over what image product that can view at a time...i have tried but its not working ... can someone help edit my code to make it work?... here is my modal code...

<!-- Modal Popup for Product Details -->
@if (selectedProduct != null)
{
    <div id="productModal" class="modal d-block" tabindex="-1">
        <div class="modal-dialog">
            <div class="modal-content shadow-lg">
                <!-- Centered Subcategory Product Title -->
                <div class="modal-header" style="text-align: center;">
                    <h5 class="modal-title" style="margin: 0 auto;">
                        @(productSliderStates.ContainsKey(selectedProduct.Name)
                          ? productSliderStates[selectedProduct.Name].sliderProducts[productSliderStates[selectedProduct.Name].currentIndex].Name
                          : selectedProduct.Name)
                    </h5>
                    <button type="button" class="close-btn"
                            @onclick="CloseModalAndOrderPopup"
                            style="font-size: 0.8rem; padding: 5px 10px;">
                        X
                    </button>
                </div>

                <!-- Modal Body -->
                <div class="modal-body position-relative">
                    <!-- Left Navigation Button -->
                    <button class="nav-btn left-btn"
                            style="position: absolute; left: 10px; top: 40%; transform: translateY(-50%); z-index: 1040;"
                            @onclick="PreviousSubCategory">
                        &lt;
                    </button>

                    <!-- Product Image -->
                    <img src="@(productSliderStates.ContainsKey(selectedProduct.Name)
                              ? productSliderStates[selectedProduct.Name].sliderProducts[productSliderStates[selectedProduct.Name].currentIndex].ImageUrl
                              : selectedProduct.ImageUrl)"
                         alt="@(productSliderStates.ContainsKey(selectedProduct.Name)
                              ? productSliderStates[selectedProduct.Name].sliderProducts[productSliderStates[selectedProduct.Name].currentIndex].Name
                              : selectedProduct.Name)"
                         class="img-fluid mb-3 modal-image"
                         style="display: block; margin: auto;">

                    <!-- Right Navigation Button -->
                    <button class="nav-btn right-btn"
                            style="position: absolute; right: 10px; top: 40%; transform: translateY(-50%); z-index: 1040;"
                            @onclick="NextSubCategory">
                        &gt;
                    </button>

                    <!-- Main Category Description -->
                    <div style="white-space: normal; word-wrap: break-word; max-height: 300px; overflow-y: auto; margin-bottom: 15px;">
                        <p><strong>Main Category Description:</strong> @selectedProduct.Description</p>
                    </div>

                    <!-- Subcategory Product Details -->
                    <div style="white-space: normal; word-wrap: break-word; max-height: 300px; overflow-y: auto;">
                        <p><strong>Name:</strong> @(productSliderStates.ContainsKey(selectedProduct.Name)
                                                    ? productSliderStates[selectedProduct.Name].sliderProducts[productSliderStates[selectedProduct.Name].currentIndex].Name
                                                    : selectedProduct.Name)</p>
                        <p><strong>Description:</strong> @(productSliderStates.ContainsKey(selectedProduct.Name)
                                                         ? productSliderStates[selectedProduct.Name].sliderProducts[productSliderStates[selectedProduct.Name].currentIndex].Description
                                                         : selectedProduct.Description)</p>
                        <p><strong>Price:</strong> GHS @(productSliderStates.ContainsKey(selectedProduct.Name)
                                                        ? productSliderStates[selectedProduct.Name].sliderProducts[productSliderStates[selectedProduct.Name].currentIndex].Price
                                                        : selectedProduct.Price)</p>
                        <p><strong>Rating:</strong> ⭐️ @(productSliderStates.ContainsKey(selectedProduct.Name)
                                                          ? productSliderStates[selectedProduct.Name].sliderProducts[productSliderStates[selectedProduct.Name].currentIndex].Rating
                                                          : selectedProduct.Rating) / 5</p>
                        <p><strong>Info:</strong> @(productSliderStates.ContainsKey(selectedProduct.Name)
                                                    ? productSliderStates[selectedProduct.Name].sliderProducts[productSliderStates[selectedProduct.Name].currentIndex].Info
                                                    : selectedProduct.Info)</p>
                    </div>
                </div>

                <!-- Modal Footer -->
                <div class="modal-footer">
                    <button class="btn btn-primary" onclick="OpenOrderPopup()">Place Order</button>
                </div>
            </div>
        </div>
    </div>
}


my script that was supposed to make the image product changing or cycling stop while i control it using the <> right and left navigation buttons.

    <script>
        let modalImageInterval;

        // Start modal image slider with a 60-second delay
        function startModalImageSlider(images) {
            let currentIndex = 0;

            // Ensure there's at least one image in the array
            if (images.length === 0) {
                console.error("No images available to display.");
                return;
            }

            // Initialize the interval to change images
            modalImageInterval = setInterval(() => {
                currentIndex = (currentIndex + 1) % images.length; // Cycle through the array
                const modalImageElement = document.querySelector('.modal-image');
                if (modalImageElement) {
                    modalImageElement.src = images[currentIndex]; // Update image source
                    console.log(`Modal image changed to index ${currentIndex}`);
                } else {
                    console.error("Modal image element not found.");
                }
            }, 60000); // Set delay to 60 seconds
        }

        // Stop modal image slider
        function stopModalImageSlider() {
            clearInterval(modalImageInterval);
            console.log("Modal image slider stopped.");
        }

        // Open product modal and start image slider
        function openProductModal(product) {
            const modalElement = document.getElementById('productModal');
            const images = product.sliderProducts.map(sliderProduct => sliderProduct.ImageUrl); // Gather image URLs

            if (modalElement) {
                modalElement.style.display = 'block'; // Display the modal
                console.log("Product modal opened.");
                startModalImageSlider(images); // Start the image slider
            } else {
                console.error("Product modal element not found!");
            }
        }

        // Close product modal and stop image slider
        function closeProductModal() {
            const modalElement = document.getElementById('productModal');
            if (modalElement) {
                modalElement.style.display = 'none'; // Hide the modal
                console.log("Product modal closed.");
            } else {
                console.error("Product modal element not found!");
            }
            stopModalImageSlider(); // Stop the slider when closing the modal
        }
    </script>

Developer technologies ASP.NET ASP.NET Core
{count} votes

2 answers

Sort by: Most helpful
  1. Anonymous
    2025-04-01T09:02:30.0266667+00:00

    Hi @KwebenaAcquah-9104,

    Your shared code is not enough to reproduce your issue. Any way, here is a whole working demo you could follow which is based on Blazor Server App:

    Razor Component

    @page "/productmodal"
    @rendermode InteractiveServer
    @inject IJSRuntime JS
    <button @onclick="OpenModal" class="btn btn-primary">Open Modal</button>
    @if (selectedProduct != null)
    {
        <div id="productModal" class="modal d-block" tabindex="-1">
            <div class="modal-dialog">
                <div class="modal-content shadow-lg">
                    <!-- Header -->
                    <div class="modal-header" style="text-align: center;">
                        <h5 class="modal-title">@CurrentProduct.Name</h5>
                        <button type="button" class="close-btn" @onclick="CloseModal" style="font-size: 0.8rem; padding: 5px 10px;">X</button>
                    </div>
                    <!-- Body -->
                    <div class="modal-body position-relative">
                        <!-- Navigation Buttons -->
                        <button class="nav-btn left-btn" @onclick="PreviousSubCategory" style="position: absolute; left: 10px; top: 40%; transform: translateY(-50%);">&lt;</button>
                        <img src="@CurrentProduct.ImageUrl" alt="@CurrentProduct.Name" class="img-fluid mb-3 modal-image" style="display: block; margin: auto;">
                        <button class="nav-btn right-btn" @onclick="NextSubCategory" style="position: absolute; right: 10px; top: 40%; transform: translateY(-50%);">&gt;</button>
                        <!-- Details -->
                        <div>
                            <p><strong>Description:</strong> @CurrentProduct.Description</p>
                            <p><strong>Price:</strong> GHS @CurrentProduct.Price</p>
                            <p><strong>Rating:</strong> ⭐️ @CurrentProduct.Rating / 5</p>
                        </div>
                    </div>
                    <!-- Footer -->
                    <div class="modal-footer">
                        <button class="btn btn-primary" onclick="OpenOrderPopup()">Place Order</button>
                    </div>
                </div>
            </div>
        </div>
    }
    @code {
        private Dictionary<string, ProductSliderState> productSliderStates;
        private Product selectedProduct;
        private string productCategoryKey = "Phones";
        protected override async Task OnInitializedAsync()
        {
            // Sample data
            productSliderStates = new Dictionary<string, ProductSliderState>
                {
                    ["Phones"] = new ProductSliderState
                    {
                        currentIndex = 0,
                        sliderProducts = new List<Product>
                    {
                        new Product { Name = "Phone A", Description = "Description A", Price = 1000, Rating = 4.5, ImageUrl = "images/phoneA.png" },
                        new Product { Name = "Phone B", Description = "Description B", Price = 1200, Rating = 4.7, ImageUrl = "images/phoneB.png" },
                        new Product { Name = "Phone C", Description = "Description C", Price = 900, Rating = 4.0, ImageUrl = "images/phoneC.png" }
                    }
                    }
                };
            selectedProduct = productSliderStates[productCategoryKey].sliderProducts[0];
        }
        private async Task OpenModal()
        {
            var images = productSliderStates[productCategoryKey].sliderProducts.Select(p => p.ImageUrl).ToList();
            await JS.InvokeVoidAsync("openProductModal", images); // Awaited to ensure correct initialization
        }
        private async Task CloseModal()
        {
            await JS.InvokeVoidAsync("closeProductModal");
        }
        private async Task PreviousSubCategory()
        {
            var state = productSliderStates[productCategoryKey];
            state.currentIndex = (state.currentIndex - 1 + state.sliderProducts.Count) % state.sliderProducts.Count;
            selectedProduct = state.sliderProducts[state.currentIndex];
            // Sync with JS
            await JS.InvokeVoidAsync("updateModalImage", selectedProduct.ImageUrl);
        }
        private async Task NextSubCategory()
        {
            var state = productSliderStates[productCategoryKey];
            state.currentIndex = (state.currentIndex + 1) % state.sliderProducts.Count;
            selectedProduct = state.sliderProducts[state.currentIndex];
            // Sync with JS
            await JS.InvokeVoidAsync("updateModalImage", selectedProduct.ImageUrl);
        }
        private Product CurrentProduct => productSliderStates[productCategoryKey].sliderProducts[productSliderStates[productCategoryKey].currentIndex];
        private class Product
        {
            public string Name { get; set; }
            public string Description { get; set; }
            public double Price { get; set; }
            public double Rating { get; set; }
            public string ImageUrl { get; set; }
        }
        private class ProductSliderState
        {
            public int currentIndex { get; set; }
            public List<Product> sliderProducts { get; set; }
        }
    }
    

    JS

    let images = [];
    let currentIndex = 0;
    let modalImageInterval;
    function openProductModal(imageUrls) {
        images = imageUrls;
        currentIndex = 0;
        updateModalImage();
        document.getElementById('productModal').style.display = 'block';
        // Start Auto-Cycling
        startModalImageSlider();
    }
    // Dynamically update modal image
    function updateModalImage(imageUrl) {
        if (imageUrl) {
            document.querySelector('.modal-image').src = imageUrl;
        } else {
            document.querySelector('.modal-image').src = images[currentIndex];
        }
    }
    // Start Automatic Cycling
    function startModalImageSlider() {
        stopModalImageSlider(); // Ensure no duplicate intervals
        modalImageInterval = setInterval(() => {
            currentIndex = (currentIndex + 1) % images.length;
            updateModalImage();
        }, 60000); // Every 60 seconds
    }
    // Stop Automatic Cycling
    function stopModalImageSlider() {
        clearInterval(modalImageInterval);
    }
    // Close Modal
    function closeProductModal() {
        stopModalImageSlider();
        document.getElementById('productModal').style.display = 'none';
    }
    

    If the answer is the right solution, please click "Accept Answer" and kindly upvote it. If you have extra questions about this answer, please click "Comment".

    Note: Please follow the steps in our documentation to enable e-mail notifications if you want to receive the related email notification for this thread.

    Best regards,
    Rena

    0 comments No comments

  2. Danny Nguyen (WICLOUD CORPORATION) 165 Reputation points Microsoft External Staff
    2025-06-27T09:40:11.6533333+00:00

    Hi @KwebenaAcquah-9104

    I've recreated a minimal demo based on your code, and from what I've seen, to stop your image modal to automatically scrolling, you need to stopModalImageSlider() at the start of StartModalImageSlider() in your Javascript file and also ModalImageInterval to null like so:

    function stopModalImageSlider()
    	if (modalImageInterval) {
    		clearInterval(modalImageInterval);
    		modalImageInterval = null;
    	};
    

    I took inspiration from the answer from Anonymous here, here is my implementation of your problem.

    ImagesModal.razor:

    @page "/imagemodal"
    @rendermode InteractiveServer
    @inject IJSRuntime JS
     
    <h3>Image Groups</h3>
    <div>
    <button class="btn btn-primary" @onclick="() => OpenModal(1)">Open Group 1</button>
    <button class="btn btn-primary" @onclick="() => OpenModal(2)">Open Group 2</button>
    <button class="btn btn-primary" @onclick="() => OpenModal(3)">Open Group 3</button>
    </div>
     
    @if (showModal)
    {
    <div id="imageModal" class="modal d-block" tabindex="-1">
    <div class="modal-dialog">
    <div class="modal-content shadow-lg">
    <div class="modal-header" style="text-align: center;">
    <h5 class="modal-title">Group @currentGroup Images</h5>
    <button type="button" class="close-btn" @onclick="CloseModal" style="font-size: 0.8rem; padding: 5px 10px;">X</button>
    </div>
    <div class="modal-body position-relative">
    <button class="nav-btn left-btn" @onclick="PreviousImage" style="position: absolute; left: 10px; top: 40%; transform: translateY(-50%);">&lt;</button>
    <img src="@CurrentImage" alt="Group Image" class="img-fluid mb-3 modal-image" style="display: block; margin: auto; max-height: 400px;">
    <button class="nav-btn right-btn" @onclick="NextImage" style="position: absolute; right: 10px; top: 40%; transform: translateY(-50%);">&gt;</button>
    </div>
    </div>
    </div>
    </div>
    }
     
    @code {
        private bool showModal = false;
        private int currentGroup = 1;
        private List<string> images = new();
        private int currentIndex = 0;
        private DotNetObjectReference<ImageModal>? dotNetRef;
     
        private readonly Dictionary<int, int> groupImageCounts = new()
        {
            [1] = 5,
            [2] = 3,
            [3] = 4
        };
     
        private Dictionary<int, List<string>> groupImages;
     
        protected override void OnInitialized()
        {
            groupImages = new Dictionary<int, List<string>>();
            foreach (var group in groupImageCounts)
            {
                var images = new List<string>();
                for (int i = 1; i <= group.Value; i++)
                {
                    images.Add($"images/{group.Key}/image{i}.jpg");
                }
                groupImages[group.Key] = images;
            }
        }
     
        private string CurrentImage => images.Count > 0 ? images[currentIndex] : "";
     
        private async Task OpenModal(int group)
        {
            currentGroup = group;
            images = groupImages.ContainsKey(group) ? groupImages[group] : new List<string>();
            currentIndex = 0;
            showModal = true;
     
            dotNetRef = DotNetObjectReference.Create(this);
            await JS.InvokeVoidAsync("openImageModal", images, dotNetRef);
        }
     
        private async Task CloseModal()
        {
            showModal = false;
            await JS.InvokeVoidAsync("closeImageModal");
            dotNetRef?.Dispose();
        }
     
        private async Task NextImage()
        {
            currentIndex = (currentIndex + 1) % images.Count;
            await JS.InvokeVoidAsync("goToImage", currentIndex);
            StateHasChanged();
        }
     
        private async Task PreviousImage()
        {
            currentIndex = (currentIndex - 1 + images.Count) % images.Count;
            await JS.InvokeVoidAsync("goToImage", currentIndex);
            StateHasChanged();
        }
     
        [JSInvokable]
        public Task OnJsImageChanged(int newIndex)
        {
            currentIndex = newIndex;
            StateHasChanged();
            return Task.CompletedTask;
        }
    }
    

    ImagesModal.razor.js:

    let modalImageInterval = null;
    let images = [];
    let currentIndex = 0;
    let dotNetHelper = null;
    
    window.openImageModal = function (imageList, dotNetRef) {
        images = imageList;
        currentIndex = 0;
        dotNetHelper = dotNetRef;
    
        const modal = document.getElementById('imageModal');
        if (modal) {
            modal.style.display = 'block';
        }
    
        startImageInterval();
    };
    
    function startImageInterval() {
        stopImageInterval(); // Ensure no duplicate intervals
        modalImageInterval = setInterval(() => {
            currentIndex = (currentIndex + 1) % images.length;
            if (dotNetHelper) {
                dotNetHelper.invokeMethodAsync('OnJsImageChanged', currentIndex);
            }
        }, 2000); // Change image every 2 seconds
    }
    
    window.closeImageModal = function () {
        const modalElement = document.getElementById('imageModal');
        if (modalElement) {
            modalElement.style.display = 'none';
            console.log("Image modal closed.");
        } else {
            console.error("Image modal element not found!");
        }
    
        stopImageInterval();
    };
    
    window.stopImageInterval = function () {
        if (modalImageInterval) {
            clearInterval(modalImageInterval);
            modalImageInterval = null;
        }
        dotNetHelper = null;
    };
    
    window.goToImage = function (index) {
        currentIndex = index;
        if (dotNetHelper) {
            dotNetHelper.invokeMethodAsync('OnJsImageChanged', currentIndex);
        }
    };
    
    

    If you have any problems, feel free to reach out.

    0 comments No comments

Your answer

Answers can be marked as Accepted Answers by the question author, which helps users to know the answer solved the author's problem.