Ensuring that the desired DOM elements have loaded before attempting to manipulate them in Vue.js

I've been struggling with this issue for the past day and I'm completely stuck. In my vue file, there's a method that operates like this:

methods: {
    showSlides(n) {
        let slides = document.getElementsByClassName("mySlides");

        slides[0].style.display = "block";
    }
},
mounted(){
    this.showSlides();
}

What it does is find all elements with the class "mySlides," store them in a variable, and then tries to change the style of the first element. This function is triggered when the component is mounted().

The problem arises when I receive an error saying

"TypeError: Cannot read property 'style' of undefined"
. It turns out that at the time this function runs, those DOM elements are indeed undefined. I only realized this when I added a @click='showSlide()' event to a button. When I click the button, the function executes successfully, but not during mounting.

Coincidentally, the code works perfectly in a plain HTML file where the script sits at the bottom of the page. This discrepancy indicates that something unusual is happening here.

Complete Code:

<template>
    <div class="wrapper">
        <div class="sight-container">
            <p class='sight-name'>{{ sight.name }}</p>
            <p>{{ sight.formatted_address }}</p>
            <p>{{ sight.formatted_phone_number }}</p>
            <p>{{ sight.international_phone_number }}</p>
            <p>{{ sight.website }}</p>


            <div class="photos-container">
                <div v-for='(image, index) in sightImages' class="mySlides">
                    <div class="numbertext">{{ index + 1 }} / {{ sightImages.length }}</div>
                    <img class='sight-photos'  :src="'https://maps.googleapis.com/maps/api/place/photo?maxwidth=1920&photoreference=' + image.photo_reference + '&key='">
                </div>

                <a class="prev" @click='plusSlides(-1)'>❮</a>
                <a class="next" @click='plusSlides(1)'>❯</a>

                <div class="caption-container">
                    <p id="caption"></p>
                </div>

                <div class="row">
                    <div v-for='(image, index) in sightImages' class="column">
                      <img class="demo cursor" :src="'https://maps.googleapis.com/maps/api/place/photo?maxwidth=1920&photoreference=' + image.photo_reference + '&key='" style="width:100%" @click="currentSlide(1)">
                    </div>
                </div>
            </div>


        </div>
    </div>
</template>

<script>
    import axios from 'axios'

    export default {
        data(){
            return {
                placeId: this.$route.params.placeid,
                sight: "",
                sightImages: [],
                slideIndex: 1
            }
        },
        methods: {
            showSlides(n) {
                let i;
                let slides = document.getElementsByClassName("mySlides");
                let dots = document.getElementsByClassName("demo");
                let captionText = document.getElementById("caption");

                if (n > slides.length) {
                    this.slideIndex = 1
                }
                if (n < 1) {
                    this.slideIndex = slides.length
                }
                for (i = 0; i < slides.length; i++) {
                    slides[i].style.display = "none";
                }
                for (i = 0; i < dots.length; i++) {
                    dots[i].className = dots[i].className.replace(" active", "");
                }

                slides[this.slideIndex-1].style.display = "block";
                dots[this.slideIndex-1].className += " active";
                captionText.innerHTML = dots[this.slideIndex-1].alt;
            },
            plusSlides(n) {
                this.showSlides(this.slideIndex += n);
            },
            currentSlide(n) {
                this.showSlides(this.slideIndex = n);
            }
        },
        mounted(){
            axios.get('/getSight/' + this.placeId)
            .then(response => {
                this.sight = response.data.result.result
                this.sightImages = response.data.result.result.photos
            }).catch((error) => console.log(error));

            this.showSlides(this.slideIndex);
        }
    }
</script>

Answer №1

It seems like the issue lies in how you are utilizing it.

Typically, the mounted method is invoked after the component's DOM has been rendered, making this.$el accessible at that point.

However, within the mounted method, you are executing an asynchronous operation that updates the data, and consequently the DOM, upon completion. The problem arises when you attempt to utilize the result before it is available.

The correct approach would be as follows:

mounted() {
  axios.get('/getSight/' + this.placeId)
       .then(response => {
         this.sight = response.data.result.result;
         this.sightImages = response.data.result.result.photos;
         this.$nextTick(() => {
           this.showSlides(this.slideIndex);
         });
       }).catch((error) => console.log(error));
}

Here's a tip: Instead of using el.className += ... or el.className.replace(...), consider employing el.classList.add(...) and el.classList.remove(...).

For more information, refer to the documentation on: Element.classList

Similar questions

If you have not found the answer to your question or you are interested in this topic, then look at other similar questions below or use the search

How can you achieve the effect of "hovering over an image to automatically start playing a muted video within the image itself"?

[![enter image description here][1]][1]I am working with WordPress and Elementor, and I want to create a hover effect where an image triggers a muted video to play within the image area on mouseover. The video should stop playing when the mouse is not hove ...

Every time I insert a new column, the table in Vue 3 undergoes a reload

When I submit a new message to be rendered in the table, the entire table reloads and causes a flicker effect. This issue only started when I switched to using a table; previously, when creating dynamic div elements, I didn't experience this problem. ...

Having trouble capturing a photo from webcam using HTML5 and getUserMedia() in Google Chrome upon initial page load

Using the information from an article on HTML5Rocks, I am attempting to create a tool that can capture photos from a webcam. Here is an excerpt of my HTML code: <button type="button" name="btnCapture" id="btnCapture">Start camera</button>< ...

Wheelnav.js implementing a dynamic bouncing animation

I'm currently in the process of working on a pie menu with wheelnav.js and everything is going smoothly so far. However, I can't seem to find any information in the wheelnav.js documentation on how to eliminate the bouncing effect when a menu cho ...

Ensure that the line above is shorter in length compared to the following line

Is there a way to ensure that the previous line of text is always shorter than the next one, even if the length of the text is unknown? For example: Lorem ipsum dolor sit amet, consectetur adipiscing et libero posuere pellentesque. Vivamus quis nulla jus ...

Any ideas on how to extract binary data from PHP passthru using a JavaScript ajax request?

I am facing an issue with retrieving and playing an audio file from a server using JavaScript. The ajax call in my code doesn't seem to callback, and I'm not certain if I'm handling the audio correctly in JavaScript. Below is the PHP file t ...

Is the Vue router preloading each view before displaying it, or does it load the view server only upon request?

When I refer to preloading, I am questioning whether the browser loads all views at once or only loads the desired views from the server upon request. ...

Nuxt Vue's new feature integrates Mermaid support for enriched content creation

After following the recommended steps, I attempted to integrate mermaid support into my Vue application. The process is outlined here If you'd like to see a demo, it's available here Utilizing Mermaid.vue <template> <div class=&quo ...

The menu field remains open even after clicking on the menu

I have encountered an issue with my code. Here is a DEMO that I created on jsfiddle.net Currently, when you click on the red div, the menu opens. However, if you click on the menu items, the menu area does not close. What do I need to do in order to clo ...

Tips for transitioning this JavaScript code into jQuery syntax

Below is my JavaScript code: javascript: function executeCode() { var d = document; try { if (!d.body) throw (0); window.location = 'http://www.example.com/code?u=' + encodeURIComponent(d.location.href); } catch (e) { ...

Send users from the web (using JavaScript) to the Windows Phone app, and if the app is not installed, direct them

In the following code snippet, I am using angular.js to detect the mobile platform and redirect to the native app. If the app is not installed, it will redirect to the market: $scope.isMobile = { Android: function() { return navigator.userAgent.ma ...

Can someone explain the meaning of this code?

Recently, I came across a project where this line of code was used in a jQuery script. I'm not sure of its purpose and would appreciate some help understanding why it was included. If necessary, I can provide the entire function for reference. $("#ta ...

Easy steps for integrating Vuex 3 with Vue 2.7

After using yarn create nuxt-app command, I noticed in the package.json file the following: "dependencies": { "nuxt": "^2.15.8", "vue": "^2.7.10", }, My project requires Vuex, specifically version 3 ...

Interactive front end design for decision trees

On the front end, I aim to enable users to influence the outcome of a Decision Tree based on their selections. For my Django-React App, I have adopted the style and tree example from the codeplayer. You can find it here: I am tasked with creating an unor ...

Is it a good idea to relocate the document.ready function into its own JavaScript function?

Can the following code be placed inside a separate JavaScript function within a jQuery document.ready, allowing it to be called like any other JavaScript function? <script type="text/javascript"> $(document).ready(function() { $('div#infoi ...

Tips for minimizing the transfer time of large arrays using ajax

https://i.stack.imgur.com/IP0oe.pngDescription I am currently working on transferring a JSON object from the server to the client using PHP and JavaScript via AJAX. The JSON object contains a large array (200x200) of integers. The server is running on lo ...

Unlocking the potential of input values in Angular.jsDiscovering the secret to

I'm currently experimenting with the angular date picker directive. My goal is to retrieve the entered date value from the date picker and log it to the console. However, all of my attempts so far have been unsuccessful. Here's a snippet of my c ...

jQuery fails to modify HTML according to its intended purpose

I've been struggling to update a price using JQuery. Even though the code seems fine when I check the console, the HTML doesn't reflect the changes. Additionally, when I try to log console.log(newPrc), it gives an error saying "newPrc" is not def ...

Updating the value of the variable using ng-submit

My application displays Quantity: {{num}}. The default value is set to 3 in the scope. The objective is to click on: <form ng-submit="addContact()"> <input class="btn-primary" type="submit" value="Add Contact"> </form> and to up ...

The Vue and Typescript webpage is not appearing in the GAS sidemenu template

I am tasked with developing an application for Google Sides using Vue + Typescript to enhance its functionality with an extra menu feature. You can find a sample without Typescript here. The result is visible in this screenshot: https://gyazo.com/ed417ddd1 ...