Skip to content
Advertisement

Vue.js Axios bug HTTP request change my array but don’t show change

I have a very strange problem in vue.js/axios.

Scenario 1 : clear my products variable BEFORE send an HTTP request (see “<<<<< SCENARIO 1” mark). Then set products variable with a new array. It works but we see a flicker (due to the HTTP request duration). So I decided to clear the products variable IN the request.

Scenario 2 : clear my products variable IN the HTTP request. (see “<<<<< SCENARIO 2” mark).

But I don’t know why in Scenario 2 : my products variable is modified but the View don’t change ! So my product variable has 3 products with related quantity. Then quantity of one product change so I clear the product variable and refresh with the HTTP request. All is the same but quantity of 1 product has changed. But the view don’t reflect this !

let Cart = {

    components: { Product },

    data: function() {
        return {
            products: []
        }
    },

    template: "<div><h3>Cart:</h3>" +
        '<product @productChanged="updateProductsCart(product)"' +
        'style="display: inline-block; max-width: 90px;" v-for="product in products"' +
        ':id="product.id" :name="product.name" :priceWithCurrency="product.priceWithCurrency"' +
        ':initQuantity="product.initQuantity" :picture="product.picture" :hasDeletedBtn="true"' +
        ':isProductRefreshAuto="false"></product>' +
    "</div>",

    methods: {

        getAllProducts: function () {

            let $this = this;
            $this.clearProductsList();<<<<< SCENARIO 1

            tdtdapi.get( '/cart/products/me', configs

            ).then(function (response) {

                $this.clearProductsList();<<<<< SCENARIO 2

                console.log("getAllProducts.then >")
                console.log(response)
                let products = [];

                for( let i = 0, l = response.data.length; i < l; i++ ){
                    let product      = response.data[i],
                        productToAdd = {
                            "name": "Product ",//todo delete raw value
                            "priceWithCurrency": 45
                        };
                    //todo: create a class Product
                    for( let prop in product ){
                        if( prop === "product" )     productToAdd.id = product[prop];
                        if( prop === "name" )        productToAdd.name = product[prop];
                        if( prop === "quantity" )    productToAdd.initQuantity = product[prop];
                        // if( prop === "description" ) productToAdd.description = product[prop];
                        if( prop === "price" )       productToAdd.priceWithCurrency = product[prop];
                        if( prop === "picture" )     productToAdd.picture = product[prop];
                    }
                    products.push(productToAdd);
                }

                $this.setProducts(products);

            }).catch(function (error) {
                console.log(error);
            });
        },

        updateProductsCart: function( product ) {
            console.log("updateProductsCart >")
            console.log(product)
            this.getAllProducts();
        },

        setProducts: function(products) {
            console.log("setProducts >")
            console.log(products)
            this.products = products;
            console.log(this.products)
        },

        clearProductsList: function() {
            this.products.splice( 0, this.products.length );
        }
    },

    mounted() {
        this.getAllProducts();
    },

    computed: {

    }
};


var app = new Vue({
    el: "#app",

    components: {
        "ProductsList": ProductsList,
        "Cart": Cart
    }
});

There is the Product component if that help :

let Product = {

    data() {
        return {
            quantity: this.initQuantity,
            price: this.getPriceWithoutSymbols()
        }
    },

    props: {
        id: { type: Number, required: true },
        name: { type: String, required: true },
        description: { type: String, default: "" },
        priceWithCurrency: { type: Number, required: true },
        initQuantity: { type: Number, default: 0 },
        picture: { type: String, default: "" },
        hasDeletedBtn: { type: Boolean, default: false },
        isProductRefreshAuto: { type: Boolean, default: true }
    },

    template: '<article :id="id">'  +
    '<div>{{ name }}</div>' +
    '<div>{{ description }}</div>' +
    '<div>{{ price }}</div>' +
    '<div><img :src="picture"/></div>' +
    '<div>Quantity: {{ quantity }}</div>' +
    '<div>Total for this product: {{ totalPrice }}</div>' +
    '<div>' +
    '<button @click="decrementQuantity" type="button">-</button>' +
    '<button @click="incrementQuantity" type="button">+</button>' +
    '<br /><button v-if="hasDeletedBtn" @click="deleteProductQuantity" type="button">Delete product</button>' +
    '</div>' +
    '</article>',

    methods: {

        addQuantity( valueToAdd ){

            //if quantity 0 to 1 ==> post
            if( (this.quantity === 0) && (valueToAdd >= 1) ){
                this.postProductQuantity(valueToAdd);
            }

            //if quantity 1 to 0 ==> delete
            else if( (this.quantity === 1) && (valueToAdd === -1) ){
                this.deleteProductQuantity();
            }

            //else ==> put
            else{
                this.putProductQuantity(valueToAdd);
            }
        },

        postProductQuantity(valueToAdd){
            console.log("POST")
            let $this = this;
            tdtdapi.post( '/cart/products/me', querystring.stringify({
                    product: $this.id,
                    quantity: valueToAdd
                }), configs
            ).then(function (response) {
                console.log(response);
                $this.setQuantity(response.data.quantity);
            }).catch(function (error) {
                console.log(error);
            });
        },

        putProductQuantity(valueToAdd){
            console.log("PUT")
            let $this = this;
            tdtdapi.put( '/cart/products/me', querystring.stringify({
                    product: $this.id,
                    quantity: ($this.quantity + valueToAdd)
                }), configs
            ).then(function (response) {
                console.log(response);
                $this.setQuantity(response.data.quantity);
            }).catch(function (error) {
                console.log(error);
            });
        },

        deleteProductQuantity(){
            console.log("DELETE")
            let $this = this;
            tdtdapi.delete( '/cart/products/me/' + this.id, configs
            ).then(function (response) {
                console.log(response);
                $this.setQuantity(0);//todo: use v-show to hide product when (this.quantity === 0)
            }).catch(function (error) {
                console.log(error);
            });
        },

        emitChanged() {
            this.$emit( "productChanged" );
        },

        incrementQuantity(){
            this.addQuantity(1);
        },

        decrementQuantity( product ){
            console.log(product)
            // if( this.quantity >= 1 ){
            //     this.addQuantity(-1);
            // }
        },

        getPriceWithoutSymbols(){
            //todo: if price contains currency, when need to get only the value
            return this.priceWithCurrency;
        },

        setQuantity( quantity ){
            if( this.isProductRefreshAuto ){
                this.quantity = quantity;
            }
            this.emitChanged();
        }
    },

    computed: {
        totalPrice: function(){
            return (this.quantity * this.price).toFixed(2);
        }
    }
};

Advertisement

Answer

The problem is that we must refresh the data of Product with the props.

Basically when the parent (here the Cart component) change the quantity of Product with the props (here initQuantity), we must say to Product instance that he must change is data (here quantity) with his props (initQuantity).

So we must add a watch at the end of Product component :

    computed: {
        ...
    },

    watch: {
        initQuantity( newQuantity ){
            this.quantity = newQuantity;
        }
    }

I found my answer here

User contributions licensed under: CC BY-SA
7 People found this is helpful
Advertisement