Spinner Vue Displays while Loading Image from a URL

I am trying to display a loader spinner while an image is loading, but I am having trouble implementing this.

Even after debugging and getting true and false values in the console, the spinner is still not showing up.

<template>
    <div class="KingOfMountain">
        <Spinner v-if="isLoading"/> //// ERROR
        <div v-else class="container">
            <div v-if="!isEndGameKing" class="choices">
                <p id="score">{{ currentCountKing }}/{{ ALL_FILMS.length - 1 }}
                <p/>
                <div class="photos">
                    <div class="first__film">
                        <img :src="firstFilm.Poster" :alt="firstFilm.title" @click="chooseLeftFilm">
                        <p id="title--film">{{ firstFilm.title }}</p>
                    </div>
                    <div class="second__film">
                        <img :src="secondFilm.Poster" :alt="secondFilm.title" @click="chooseRightFilm">
                        <p id="title--film">{{ secondFilm.title }}</p>
                    </div>
                </div>
            </div>
            <div v-else class="winner">
                <p id="winner--title">Winner</p>
                <img :src="firstFilm.Poster" :alt="firstFilm.title">
            </div>
        </div>
    </div>
</template>

<script>
import game from "@/mixins/game";
import Spinner from "@/components/Spinner/Spinner"; //all good in css . it works


export default {
    name: "KingOfMountain",
    data() {
        return{
            isLoading:false
        }
    },
    components: {Spinner},
    methods: {
        chooseLeftFilm() {
            this.isLoading=true
            this.redirectToResultKing() // it is method in mixins (all Good, it works)
            this.isLoading=false
        },
        chooseRightFilm() {
            this.isLoading=true
            this.firstFilm = this.secondFilm;
            this.redirectToResultKing() // it is method in mixins (all Good, it works)
            this.isLoading=false
        }
    },
}
</script>

If I use the following code snippet, the spinner appears:

chooseLeftFilm() {
    this.isLoading=true
    this.redirectToResultKing() // it is method in mixins (all Good, it works)
},

//It will show the spinner forever

Can anyone help me with a better way to implement the spinner functionality?

This is my mixins:

export default {

methods: {
    updateFilm() {
        //Here I randomly select 2 images from Vuex and manipulate them
        this.currentCountKing++;
        this.allFilmsKingCopy = this.allFilmsKingCopy.filter(val => val !== this.secondFilm);
        this.secondFilm = this.allFilmsKingCopy[Math.floor(Math.random() * this.allFilmsKingCopy.length)];
    },
    redirectToResultKing() {
        if (this.currentCountKing === this.ALL_FILMS.length - 1) {
            this.isEndGameKing = true;
        } else {
            this.updateFilm();
        }
    }
},
computed: {
    ...mapGetters(['ALL_FILMS']),
},

This is my Vuex:

export default {
    state: {
        films: [],
    },
    actions: {
        async getFilms({commit}) {
            const data = await fetch(URL);
            const dataResponse = await data.json();
            const films=dataResponse.data;
            commit("setData", films);
        },
    },
    mutations: {
        setData(state, films) {
            state.films = films;
        },
    },
    getters: {
        ALL_FILMS(state) {
            return state.films;
        },
    }
}

Answer №1

One common method is to first load the image using an Image object, then utilize the load event to wait for the data to be fully loaded before displaying a spinner in the meantime. Once the image URL is set, the img element will be updated immediately:

const imgUrl = 'https://picsum.photos/200?random='
let imgCount = 0

const App = {
  template: `
    <div style="display: flex;">
      <div>
        <button @click="loadImage">Load new image</button>
      </div>
      <div v-if="isLoading">LOADING....</div>
      <img :src="src"/>
    </div>
  `,
  data() {
    return {
      isLoading: false,
      src: null,
    }
  },
  methods: {
    async loadImage() {
      this.src = null
      this.isLoading = true
      const img = new Image()
      img.src = imgUrl + imgCount++
      await new Promise(resolve => img.onload = resolve)
      this.src = img.src
      this.isLoading = false
    }
  },
  created() {
    this.loadImage()
  },
}
Vue.createApp(App).mount('#app')
<div id="app"></div>
<script src="https://unpkg.com/vue@3/dist/vue.global.js"></script>


An alternative approach would be to skip the Image object and instead trigger the @load event on the img. However, this may briefly display the spinner and image simultaneously unless you hide the image with v-show:

const imgUrl = 'https://picsum.photos/200?random='
let imgCount = 0

const App = {
  template: `
    <div style="display: flex;">
      <div>
        <button @click="loadImage">Load new image</button>
      </div>
      <div v-if="isLoading">LOADING....</div>
      <img
        v-show="!isLoading"
        :src="src"
        @load="isLoading = false"
      />
    </div>
  `,
  data() {
    return {
      isLoading: false,
      src: null,
    }
  },
  methods: {
    async loadImage() {
      this.isLoading = true
      this.src = imgUrl + imgCount++
    }
  },
  created() {
    this.loadImage()
  },
}
Vue.createApp(App).mount('#app')
<div id="app"></div>
<script src="https://unpkg.com/vue@3/dist/vue.global.js"></script>

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

Unable to add new Instance Properties in Vue.js within a Laravel project

I am attempting to develop a localization property similar to __('text') in Laravel blade template. I have set up a global window variable that contains all required data under the name window.i18n Below is my resourses/js/app.js file: require(& ...

Enhance the user experience with a personalized video player interface

I am facing difficulty in creating a responsive video with custom controls. While I understand that using a <figure></figure> element and setting the width to 100% makes the video responsive, I am struggling with making the progress bar also r ...

``The vuejs component encountered an error when trying to dispatch an action with an unknown action type in vu

I've successfully implemented laravel, vue, and vuex in a different project with similar code, and it's been running smoothly. Now, I'm trying to adapt that code as a boilerplate for this project, but I'm encountering the following erro ...

"Enhance your website design with a full-width element using Boostrap that align

Whenever my div is scrolled to, it becomes fixed. At that point, I want the div to expand to full width. I achieved this by adding width: 100% to the div. However, the issue is that I want the content of the div to align with the rest of the page content, ...

Transferring the dirty state of the view to the parent form

Within my main form's markup, there is a specific structure that includes a tabset and a selectView method in the controller: <tabset vertical="true" type="pills"> <tab ng-repeat="tab in tabsViews" sele ...

The Vue.js application is failing to toggle the integrated code

I am new to using Vue and I am trying to create a vertical navigation bar. When the menu icon is clicked, the navbar should toggle. Here is my menu icon code: <button type="button" id="sidebarCollapse" class="btn btn-info [collapsed?'': ...

Can jQuery be used to edit an XML file?

Can XML files be updated using jQuery, or is server-side scripting necessary for this task? Thank you ...

Should I use jQuery's .on() method or plain JavaScript function()?

I am currently working on pages that are constructed using ajax calls to the server, which means I am using .on() to attach event handlers to new items. However, I am curious whether it would be more effective to use the traditional javascript:function() ...

What is the best way to conceal a parent element with jquery?

Let's say we have the following HTML structure: <li class="fooli"> <a class="foo" href="javascript:foo(this);">anchor</a> </li> <li class="fooli"> <a class="foo" href="javascript:foo(this);">anchor</a> ...

Guide on updating location and reloading page in AngularJS

I have a special function: $scope.insert = function(){ var info = { 'username' : $scope.username, 'password' : $scope.password, 'full_name' : $scope.full_name } $http({ method: &ap ...

I am working with Vue.js 2.0 and attempting to send an event from a `child component`

I've been working with Vue.js 2.0 and I'm facing an issue trying to emit an event from a child component to the parent component, but unfortunately, it's not functioning as expected. Here is a glimpse of my code: child component: <temp ...

Create a new object in Three.js every x seconds and continuously move each object forward in the Z-axis direction

I am currently developing a Three.js endless runner game where the player controls a character dodging cars on a moving road. At this early stage of development, my main challenge is to make the hero character appear to be moving forward while creating the ...

Unusual CSS hierarchy observed post AJAX content load

Currently, I am facing a puzzling issue where my CSS rules seem to be losing precedence on a page loaded via AJAX. Despite placing my custom CSS file last in the main page, allowing it to take precedence over any bootstrap styles, after loading new content ...

Guide on incorporating botframework into a mobile application...?

Recently, I developed a chatbot utilizing the MS bot framework in Nodejs. To display the chatbot in an HTML format without iframes, I incorporated a React Component from the link provided at https://github.com/Microsoft/BotFramework-WebChat. At this point, ...

I am encountering an error in Cypress when utilizing the condition with "pointer-events: none". How should I proceed to resolve this issue?

My goal is to test pagination by clicking on the Next button until it becomes disabled. Despite the code I used below, the Next button continues to be clicked even after it has the disabled class, resulting in an error being thrown by Cypress. static pag ...

Guide to building a nested React component

My custom dropdown component requires 2 props: trigger (to activate the dropdown) list (content to display in the dropdown) Below is the implementation of my component: import { useLayer } from "react-laag"; import { ReactElement, useState } fr ...

I'm looking to create an array of tags that contain various intersecting values within objectArray

Initially const array = [ { group: '1', tag: ['sins'] }, { group: '1', tag: ['sun'] }, { group: '2', tag: ['red'] }, { group: '2', tag: ['blue'] }, { grou ...

"Ionic 3: Utilizing the If Statement within the subscribe() Function for Increased Results

I added an if conditional in my subscribe() function where I used return; to break if it meets the condition. However, instead of breaking the entire big function, it only breaks the subscribe() function and continues to execute the navCtrl.push line. How ...

Employing a break statement after the default case within a switch statement even when the default is not

According to a tutorial from w3schools that discusses switch statements, it is advised: If the default case is not the last case in the switch block, it is important to remember to end it with a break statement. However, the same tutorial also explains ...

How will the presence of @types/react impact the higher-level files in my project?

https://i.sstatic.net/TfsLf.png https://i.sstatic.net/RqmMS.png Here is the structure of my directories vue node_modules src react_app node_modules @types/react package.json ...other file package.json Why does the presenc ...