0

I'm new to Vue.js and JavaScript. I just want to know how to update array (on Add/Edit/Delete) and not reloading again all the data. Only loading all data when opening page with Addresses.

This is my code:

<template v-else>
<div>
    <div class="page-header with-actions">
        <h1>Addresses</h1>
        <div class="actions">
            <b-btn @click="addAddress" variant="primary"><i class="oi oi-plus"></i> Add Address</b-btn>
        </div>
    </div>
    <div v-if="isLoaded === true">
        <div v-if="addressList.length">
            <b-form @submit.prevent="submit">
                <validation-summary :errors="errors"></validation-summary>

                <div class="row">
                    <div class="col-sm-4" v-for="address in addressList">
                        <div class="card bg-light mb-4">
                            <div class="card-header">
                                {{address.countryName}}
                                <div class="float-right">
                                    <b-btn @click="editAddress(address.id)" class="btn btn-default btn-sm" data-toggle="tooltip" title="Edit address">
                                        <i class="fa fa-edit" aria-hidden="true"></i>
                                    </b-btn>
                                    <b-btn @click="deleteAddress(address.id)" class="btn btn-default btn-sm" data-toggle="tooltip" title="Delete address">
                                        <i class="fa fa-trash" aria-hidden="true"></i>
                                    </b-btn>
                                </div>
                            </div>
                            <div class="card-body">
                                <em class="card-text">{{address.city}},</em><br />
                                <em class="card-text">{{address.streetAddress}},</em><br />
                                <em class="card-text">{{address.zip}}</em><br />
                            </div>
                        </div>
                    </div>
                </div>
            </b-form>
        </div>
        <div v-else class="alert alert-info" role="alert">
            There are no <strong>addresses</strong> yet!
        </div>
    </div>
    <add-address-modal ref="addAddressModal" @success="addressAdded"></add-address-modal>
    <edit-address-modal ref="editAddressModal" @success="addressEdited></edit-address-modal>
</div>
</template>

<script>
import Vue from 'vue';
import modalFormMixin from 'mixins/modal-form-mixin';
import formMixin from 'mixins/form-mixin';
import accountService from 'services/account-service';

import AddAddressModal from './add-address-modal';
import EditAddressModal from './edit-address-modal';

export default {
    mixins: [modalFormMixin],
    mixins: [formMixin],

    components: {
        'add-address-modal': AddAddressModal,
        'edit-address-modal': EditAddressModal
    },

    data() {
        return {
            addressList: [],
            isLoaded: false,
        }
    },

    async beforeRouteEnter(to, from, next) {
        next(async (c) => await c.initData());
    },

    methods: {
        async initData() {
            await this.loadAddressList(); //when opening page

            this.isLoaded = true;
        },

        async loadAddressList() {
            this.addressList = await accountService.getAddressList();
        },

        addAddress(data) {
            this.$refs.addAddressModal.show();
        },

        editAddress(id) {
            this.$refs.editAddressModal.show(id);
        },

        async deleteAddress(id) {
            await accountService.deleteAddress(id);

            this.loadAddressList(); //need to change

            this.$root.successToast('Address deleted');
        },

        addressAdded() {
            this.loadAddressList(); //need to change

            this.$root.successToast('Address added');
        },

        addressEdited() {
            this.loadAddressList(); //need to change

            this.$root.successToast('Address edited');
        }
    }
}
</script>

So i need to change loadAddressList() because its reloading again all the addresses data after Add/Edit/Detele. What will be the best solution for this?

4
  • Wouldn't a more straightforward approach be to actually save the addresses to the account service on edit? That way you would always load the updated list. Commented Nov 2, 2018 at 8:54
  • @Imre_G I need to update only added/edited or deleted address, not loading all list everytime... Commented Nov 2, 2018 at 9:03
  • Can you post the code to the AddAddressModal and EditAddressModal components? Commented Nov 2, 2018 at 9:12
  • @Imre_G I don't think this is necessary, this is just for modal from BootstrapVue. Commented Nov 2, 2018 at 10:18

3 Answers 3

2

I've fallen foul of this issue before. It's to do with Reactivity and how the changes might be delayed a tick.

An example solution to your problem.

methods: {
  async loadAddressList() {
    this.addressList = await accountService.getAddressList();
    await this.$nextTick() // waits for the next event tick before completeing function.
  },
}

Take a look into Async update Queue.

Also, take a look into Array Change Detection Replacing an array does some efficient operational work to reuse the DOM elements.

Best of luck.

Sign up to request clarification or add additional context in comments.

1 Comment

Thanks, i will take a look on this a little bit later.
0

I wonder if you could make use of then ? So in your initiData method for example you could do this?

async initData() {
    this.loadAddressList()
        .then(() => {
             this.isLoaded = true;
        });
    },

It means you don't need to update the loadAddressList method and make it wait or do other functionality that it really shouldn't take responsibility for?

UPDATE: You should also ensure your loadAddressList method returns some value, since it uses the async keyword returns a promise.

async loadAddressList() {
    this.addressList = await accountService.getAddressList();
    return true
},

Then the .then() would work in your initData() method.

Also see screen shot from https://javascript.info/async-await

enter image description here

2 Comments

'await' is needed because I have alert-info when there are no addresses added and without await when page is opened I can seen alert-info for a second and then addresses (if user has one or more addresses).
OK, I have updated my answer. Hope that helps. It's just a suggestion.
0

With vue 2.0 your best bet to make sure the data change trigger a dom update everytime is Vue.set with assosiative arrays (object of objects) but to be more efficient your update / create request should return the object then you can either push it in the array or use this method:

import Vue from 'vue'
createAddress(data) {
   axios.POST('your-url', data).then( address => {
       Vue.set($store.addresses, address.id, address)
   })
}

To use that you must change your array of addresses for an assosiative like this :

import Vue from 'vue'

getAddresses(state) {
   axios.GET('your-url').then(addresses => {
       addresses.forEach(address => {
            Vue.set(state.addresses, address.id, address)
       })
   })
}

You could also do that with

Object.assign(state.addresses[address.id], address)

but from my experience this sometimes does not update the dom for unknown reason.

then your address_list would have to be a computed that point to the addresses in your state management (vuex or else)

computed: {
    address_list() {
        return $store.addresses
    }
}

Comments

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.