Cycle through images that are dynamically generated from retrieved data

Although I have a functional solution for this issue, it feels messy and not the ideal way to handle it in Vue.

The challenge is fetching data from a backend related to a "Vendor" entity, which includes photos that need to be displayed on the page. The goal is to show one photo at a time and then rotate through them every 5 seconds by changing their opacity using setInterval.

I have a 'ref' for the images but cannot access it within '.then' because this.$refs is not available in created(). Furthermore, the "refs" are also unavailable in mounted() due to the asynchronous fetch call in created().

Placing setInterval in update is not an option since it would create a new listener for each update attempt (yes, I tried that...).

My current approach involves updated() setting this.photoCount whenever there's an update. setInterval is implemented in created() but remains inactive until this.photoCount is no longer null.

<template>
    <!-- Your template content here -->
</template>

<script>
export default {
    data(){
        return {
            vendor: {},
            banner: {
                displayed: false,
                type: "",
                message: ""
            },
            displayedPhoto: 0,
            photoCount: null
        }
    },

    created(){
        let token = localStorage.getItem("jwt");
        let headers = {"Content-Type": "application/json"};
        if(token !== null) headers["Authorization"] = `Bearer ${token}`;

        // Fetch vendor data
        fetch(`http://localhost:8000/vendor${document.location.pathname}`, {
            method: "get",
            headers: headers,
        })
            .then(r=>r.json())
            .then((vendor)=>{
                this.vendor = vendor;
            })
            .catch((err)=>{
                console.error(err);
            });

        // Setting up photo rotation with setInterval
        setInterval(()=>{
            if(this.photoCount !== null){
                if(this.displayedPhoto >= this.photoCount){
                    this.displayedPhoto = 0;
                }else{
                    this.displayedPhoto++;
                }
            }
        }, 5000);
    },

    updated(){
        // Calculate photo count once refs are available
        this.photoCount = this.$refs.vendorPhoto.length;
    }

What could be a more efficient and "vue-like" approach to tackle this issue? While my current solution works, it seems suboptimal.

Answer №1

What I would do differently:

  • Avoid counting $refs. The necessary information is already present in vendor.photos.length
  • photoCount should be a computed property. Keeping it as a separate state variable risks it falling out of sync with vendor.photos.count, which could result in subtle bugs. It is best practice for derived state (e.g: computed properties, store getters) to always remain derived and not duplicate information in multiple places within the state.
  • The function that increments the displayedPhoto variable could be simplified to:
methods: {
  changePhoto() {
    this.displayedPhoto = (this.displayedPhoto + 1) % this.photoCount
  }
}
  • Fetching vendor data should be handled by a standalone method (e.g: fetchVendor). This allows for re-fetching when necessary based on business logic, without being tied to the component lifecycle.
  • I have moved the fetch operation to the mounted hook. The created hook should only contain code that needs to run before the component is added to the DOM, fetching data does not fall into that category.
    Fetching data in created can give the false impression that the component may render before the data is fetched, even if the backend is running locally. It is better to fetch data in the mounted hook and handle a suitable "loading..." state (e.g: loading indicator, placeholder image, etc...)
  • I want to highlight:
    { hidden: i !== displayedPhoto % photoCount }
    . I included the % photoCount part to cover edge cases where switching from a vendor with, for example, 10 images to one with 5 images might cause no image to appear if the displayed index exceeds 5. Adding % photoCount ensures that an image from the new vendor is displayed. Alternatively, we could watch changes in the vendor object and reset displayedPhoto to 0 when vendor changes.
  • In terms of swapping vendors, I have also implemented a more robust approach to managing the slider, ensuring that no interval is left running under any circumstances.

View the updated version here. Additional notes:

  • I had to simulate the axios request using a promise to approximate the actual response of the call.
  • I created a custom fader for images since the code for that was not provided

That covers the key updates made to the implementation.

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

Error: AngularJS form validation is not working properly

I've been following the AngularJS documentation, but I'm having trouble with my validations. The error messages are not showing up and the minimum length restrictions for the form fields are not working: <form name="callbackForm" ng-submit="r ...

What impact does incorporating a new test case have on code coverage in Jest?

I recently encountered an unexpected situation while working on a Jest test suite. Despite not making any changes to the codebase, I simply added a new test. Originally: mylibrary.js | 95.65 | 89.66 | 100 | 95.65 | 54-56,84 ------------ ...

Can the sliding transition effect used in createMaterialTopTabNavigator be implemented in createMaterialBottomTabNavigator as well?

When using createMaterialTopTabNavigator, the transition from screen to screen involves a sliding effect as you press the tabs. On the other hand, createMaterialBottomTabNavigator uses a fading-in animation for its transitions. Is there a way to combine o ...

Transmitting client-side Javascript data to backend server using Express

I am trying to fetch data from my frontend using the DOM and send it to the backend through Express but I'm unsure of how to proceed. I have used a POST method to console.log the data, but now I need help retrieving it in my Express backend. (The cons ...

Extract the content of an element and incorporate it into a script (AddThis)

HTML: <div id="file-section"> <div class="middle"> <p class="description"> Lorem ipsum... </p> </div> </div> jQuery: var share_on_addthis = { description: $('#file-section ...

What could be causing the issue with the Vue CLI not working after installation via npm 6.9.0?

Whenever I try to run the command below: vue create hello-world I receive this message : 'vue' is not recognized as an internal or external command, operable program or batch file. It's been a month and I'm still struggling to fin ...

Determine the elapsed time in seconds between two specified moments

I am trying to implement two input fields in my HTML, one for a starting point and another for an end point. The user will enter two times like this: For example: [8:15] - [14:30] alert("XXXXX seconds") I want to calculate the number of seconds between 8 ...

Struggling with rendering an HTML element utilizing jQuery's attribute functionality, encountering issues exclusively in Internet Explorer version

I need assistance with generating and inserting an HTML element using jQuery. In my code, I am including a class attribute for the element as shown below: jQuery('<li></li>', { class: "myClass" }); However, when testing in IE ...

Tips for handling Vue/Axios JSON payload sent data in Yii2

After spending some time trying to figure it out, I finally realized the solution, which was a bit obvious. I am sharing my answer here so that others can benefit from it and also to see if there is a more efficient way to handle this issue. The problem I ...

How can I efficiently add multiple items to an array and store them in async storage using React Native?

I am trying to store multiple elements in local storage using React Native. I found some helpful documentation on how to do this here. Could someone guide me on the correct way to achieve this? Here's a snippet of my code: My current approach const ...

You are trying to reference the property or method "subscribed" during the render process in Vue.js, but it is not defined on

Within my Vue subscribe-button component, I have included all the necessary parts: props, computed properties, and methods. In the computed section, I have defined the subscribed property. However, I am encountering an error: " [Vue warn]: Property o ...

ReactJS requires HTTP server to transpile babel code before running

I am a beginner when it comes to working with reactjs and I am currently in the process of setting up babel to execute babel code without having to serve HTTP files. Following the instructions on the Package Manager, I have successfully installed it along ...

Unlocking the Power of Select Options in Vue.js

I am currently learning how to use Vue.js. Below is an example of the Javascript code I have written: new Vue({ el: '#app', data: { classes: [] }, created: function () { var vm = this // Fetch API ...

The getelementbyid function is unable to locate the specified button identifier

As I dive into the world of Javascript, I wanted to create a simple input form with a corresponding response field on my website. However, I encountered an issue where using a basic submit button caused the page to refresh and erase the textfields before ...

An error occurred while trying to update with Webpack Dev Server: [HMR] Update failed due to an issue fetching the update manifest,

I encountered an issue in the browser console while attempting to live reload / HMR on Webpack. The error arises after saving a file following a change. [HMR] Update failed: Error: Failed to fetch update manifest Internal Server Error Could the failure b ...

The art of positioning images and creatively cropping

Seeking advice on allowing users to dynamically position and clip an image on a webpage. I've tried using CSS and JavaScript for clipping and resizing, but it's not working as expected. If PHP could provide a solution, that would be ideal for my ...

Tips for setting up a queue system for alert messages in Vue.js with Vuetify

Seeking assistance with modifying my code to handle multiple alerts and implement a customizable timeout duration. Any advice on how to approach this would be greatly appreciated. ~/store/toast-messages.js export const state = () => ({ color: '&a ...

Using Javascript to dynamically retrieve accordion content from a dynamically generated ID

I am currently working on developing a more intricate accordion feature. The accordion will consist of 4 buttons (section 0-3) with unique content (lorem ipsum 0-3). Clicking on "section 0" should reveal "lorem ipsum 0", while clicking on "section 1" shoul ...

Creating an image from the contents of a div is necessary in order to visually

I am looking to develop a software that can: receive text input from the user and place it in a specific div allow users to adjust font, color, and size based on their preferences enable image uploads as background save all customizations and send them v ...

Modifying the color of a specific div using jQuery

I am attempting to develop a function that changes the background color of a div when a user clicks on it and then clicks on a button. The value needs to be saved as a variable, but I'm having trouble getting it to work because it keeps saying that th ...