The reactivity of VueJs object key/value pairs is not properly maintained within a v-for loop

I'm currently facing a dilemma that I am struggling to solve effectively.

Within my view, I have a "list" of all purchased images displayed using a v-for loop. Each image includes a progress bar element which should be shown when the user clicks the download button and triggers the downloadContent function.

This is what my HTML structure looks like:

<section class="stripe">
    <div class="stripe__item card" v-for="(i, index) in purchasedImages">
        <progress-bar :val="i.download_progress"
                      v-if="i.download_progress > 0 && i.download_progress < 100"></progress-bar>
        <div class="card__wrapper">
            <img :src="'/'+i.thumb_path" class="card__img">
        </div>
        <div class="btn-img card__btn card__btn--left" @click="downloadContent(i.id_thumb, 'IMAGE', index)">
        </div>
    </div>
</section>

And here's my JavaScript code:

import Vue from 'vue'
import orderService from '../api-services/order.service';
import downloadJs from 'downloadjs';
import ProgressBar from 'vue-simple-progress';

export default {
    name: "MyLocations",
    components: {
        ProgressBar: ProgressBar
    },
    data() {
        return {
            purchasedImages: {},
            purchasedImagesVisible: false,
        }
    },
    methods: {
        getUserPurchasedContent() {
            orderService.getPurchasedContent()
                .then((response) => {
                    if (response.status === 200) {

                        let data = response.data;
                        this.purchasedImages = data.images;

                        if (this.purchasedImages.length > 0) {
                            this.purchasedImagesVisible = true;
                            // Set download progress property
                            let self = this;
                            this.purchasedImages.forEach(function (value, key) {
                                self.purchasedImages[key].download_progress = 0;
                            });
                        }
                    }
                })
        },
        downloadContent(id, type, index) {
            let self = this;
            orderService.downloadContent(id, type)
                .then((response) => {
                    let download = downloadJs(response.data.link);
                    download.onprogress = function (e) {
                        if (e.lengthComputable) {
                            let percent =  e.loaded / e.total * 100;
                            let percentage = Math.round(percent);
                            if (type === 'IMAGE') {
                            // Is this proper way to set one field reactive?
                         self.purchasedImages[index].download_progress = percentage;
                                if (percentage === 100) {
                                    self.purchasedImages[index].download_progress = 0;
                                }
                            }
                        }
                    }
                })
        },
    },
    mounted: function () {
        this.getUserPurchasedContent();
    }
};

The issue at hand is that after initiating the download by clicking the button, the content downloads successfully but the progress bar does not appear. I'm questioning whether setting the element reactively in this manner is correct. What would be the right approach? How can I ensure that

self.purchasedImages[index].download_progress
updates properly to display the progress bar?

If you require any additional information, please feel free to ask. Thank you!

Answer №1

In the following code snippet:

this.purchasedImages = data.images;

It seems that data.images is perceived as an array of objects lacking the download_progress property. Because of this, Vue cannot detect/react when changes occur.

To resolve this issue, you can utilize Vue.set:

Vue.set(self.purchasedImages[key], 'download_progress', 0);

This concept is thoroughly discussed in the Vue.js documentation.


Another approach: include the property prior to assigning to data

For the sake of completeness, you have the option to add the download_progress before setting the array to the data property. By doing so, Vue will be able to detect and react accordingly.

For instance:

let data = response.data;
this.purchasedImages = data.images.map(i => ({...i, download_progress: 0}));

if (this.purchasedImages.length > 0) {
    this.purchasedImagesVisible = true;
    // no need to set download_progress here as it was already set above
}

// Alternatively, this could be simplified to just:
this.purchasedImagesVisible = this.purchasedImages.length;




Additionally, considering it will be an array and not an object, it's advisable to declare it as such:

data() {
    return {
        purchasedImages: [], // previously: {},

Even though it doesn't have any impact since you completely overwrite purchasedImages with (

this.purchasedImages = data.images;
), specifying the type is a good practice for documentation purposes.

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

Slide back with jQuery when a user clicks anywhere on the webpage

$(".links").click(function(){ $('.slider').stop(true,false).animate({ right: "0" }, 800, 'easeOutQuint'); }, function() { $(".slider").stop(true,false).animate({ right: "-200" }, 800, 'easeInQuint'); }, 1000); I ...

Installing v8-profiler on Windows 8 (64 bit) through npm: a step-by-step guide

The v8-profiler module is widely recognized as the go-to tool for identifying memory leaks in node.js applications. However, attempting to install it with npm install v8-profiler results in an error message related to compatibility issues between 32bit an ...

JointJS: I need to extract the source value from the JSON text with the ID field

I need to extract the text value from "source":{"id": using JSON data in this specific JavaScript object : { "cells": [ { "type": "devs.Model", "size": { "width": 40, "height": 40 }, "inPorts": [""], "outPorts": ["" ...

Creating an accordion feature within an ng-repeat using AngularJS based on user clicks

When I click on the span with ng-click="click_subcat(opp.ct_nm);, the content is loaded within the <span ng-click="click_pdms(opp.sbct_nm);" style="color:white;cursor:pointer">{{opp.sbct_nm}}</span>. The issue arises when I click on that span a ...

Issue with Vuex functionality not functioning correctly when nested within an iframe across various layouts

I am currently working with two different layouts: default and main. The default layout is designed for the page view, while the main layout serves as an empty wrapper without any components. To display the main layout, it is loaded within an iframe on t ...

Changing the style of TinyMCE dropdowns using CSS

I successfully incorporated the tinyMCE editor into my Vue.js Application. init = { height: 500, menubar: false, plugins: [ 'advlist autolink lists link image charmap print preview anchor', 'searchreplace vi ...

Webpack is having trouble resolving the Vue package within the node_modules directory, specifically with vue-template-compiler

I have a basic Typescript project that includes the following code: import { parseComponent, compile as compileTemplate, ASTElement, } from "vue-template-compiler"; ... To compile this code, I use tsc with the following configuration: &quo ...

Troubleshooting error in Vue project: "hasOwnProperty" property or method not supported by object in IE11

While working on a vue app with vue advanced webpack template, I didn't pay much attention to Internet Explorer compatibility. However, today when I tried running the app on IE browser, I encountered some strange errors. https://i.stack.imgur.com/1e6 ...

Utilize Javascript to create a function that organizes numbers in ascending order

Is there a way to modify this code so that the flip clock digits appear in ascending order rather than randomly? $( '.count' ).flip( Math.floor( Math.random() * 10 ) ); setInterval(function(){ $( '.count' ).flip( Math.floor( Math.rand ...

Prevent accidental deletion of the entire document in mongoose (express.js) by selectively removing only a specific string from an array

Hey there, I'm new to this platform and my English isn't great, so apologies if I don't grasp all the nuances of my issue. I have a question about why the findOneAndDelete() method in Mongoose is deleting all documents instead of just delet ...

The functionality of Jquery UI is not compatible with version 1.12

Incorporating jQuery UI into my current project has presented some challenges. Both the jquery-ui.min.css and jquery-ui.min.js files are version 1.12, so I opted for the latest jQuery version, jquery-3.2.1.min.js. Specifically, I decided to test the datep ...

What is the reason for the addEventListener function not being able to access global variables?

I have set up an event listener function to utilize popcorn.js for displaying subtitles. Additionally, I have created functions that are unrelated to popcorn.js outside of the event listener and declared a global variable array. However, when attempting ...

JSON data localization

I am currently in the process of developing a hybrid mobile application with PhoneGap as the platform. My goal is to localize the app's data so that it can be accessed offline. Essentially, I want all JSON data received from the API to be stored local ...

Any suggestions on resolving the message "Unable to locate module './commands/${file}'"?

Can someone assist me in resolving this issue? I am trying to develop a code that includes advanced commands. Here is the code snippet: const commandFiles = fs.readdirSync('./commands/').filter(file => file.endsWith('.js&apo ...

Incorporating tawk.to into a Nuxt/Vue application

Has anyone had success implementing tawk.to in a Nuxt application? I took the initiative to create a file called "tawk.js" in my plugin folder and added the following code: var Tawk_API = Tawk_API || {}, Tawk_LoadStart = new Date() (function () { ...

What is the scope parameter for the facebook-node-sdk in node.js?

https://github.com/amachang/facebook-node-sdk I decided to utilize this module in order to create a Facebook-integrated login for my node.js project, following the example provided with express: var express = require('express'); var Facebook = ...

Having issues with Bootstrap 5 modal not functioning correctly?

I'm facing an unusual issue that I'm struggling to resolve. I'm currently utilizing Bootstrap 5 and encountered the following problem: const reportBtns = Array.from(document.querySelectorAll('.report')) reportBtns.forEach((btn) ...

"Enhanced Web Interactions with JavaScript Animations

I've been diving into my JavaScript project lately. I'm currently focusing on creating some cool animations, particularly one that involves making a ball bounce up and down. My code seems to work flawlessly for the downward bounce, but I'm f ...

What is the best way to retrieve a Rails variable that is restricted to a specific partial?

As a newcomer to Ruby on Rails, I find myself struggling to grasp the larger concept. Any assistance you can offer would be greatly appreciated. Within my application.html.haml file, I utilize =yield to pull content from ranked.html.haml. Currently, this ...

The font size varies depending on the language being used

On a single web page, there are 3 different language words displayed: Language / 한국어 / ภาษาไทย I am interested in enlarging the Thai word (ภาษาไทย) to make it stand out. <span class="thai">ภาษาไท ...