Reputation: 147
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?
Upvotes: 0
Views: 3275
Reputation: 4109
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.
Upvotes: 2
Reputation: 1
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
}
}
Upvotes: 0
Reputation: 2008
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
Upvotes: 0