Data is not updated in Vue component when emit calls function - vue.js

Note: when I upload small size image then the data refreshes and if the image is bigger like 1 mb then it doesn't refresh the data.
I have a add new product modal and when I open it as below:
<NewProduct v-if="showNewProduct" #close-modal="showNewProductModal" #success="showSuccessAlert"/>
and when I add the product and the modal is closed by emitting as below:
Products.addProduct(form)
.then(
this.$emit("closeModal"),
this.$emit("success"),
)
Then in the parent component the data is not refreshed and show the old data and if I refresh the page then it show the new data.
I get data as below in parent component:
data: function () {
return {
showNewProduct: false,
productList: [],
success: false,
};
},
mounted() {
this.getProductList();
},
methods:{
showSuccessAlert() {
this.getProductList(),
this.success = !this.success,
},
showNewProductModal() {
this.showNewProduct = !this.showNewProduct;
},
getProductList() {
User.getProductList()
.then((response) => {
this.productList = response.data;
});
},
}
My goal is that when the modal is closed then the productList should be updated as well with the newly added data without page refresh.
Add product API.
addProduct(form) {
return Api().post("/addProduct", form);
},

It is something related to asynchronous processing. Please, make sure you start fetching record only after the upload is completed.
Products.addProduct(form).then(() => { this.$emit("closeModal")} )
showNewProductModal() { this.getProductList()}

Products.addProduct(form).then(({data: product}) => {
//pass data to close model event
this.$emit("closeModal", product),
this.$emit("success"),
}
showNewProductModal(product) {
this.productList.push(product);
this.showNewProduct = !this.showNewProduct;
}

Related

Method to check if item is saved within the Nuxt Store

I currently have a Store that has the "Saved" items from a feed for a user. I'm trying to figure out the best/efficient way to check if the item is already saved within the store.
I can't think of any other way than grabbing the entire store's contents in each feed item and checking whether the id exists? Surely there's a better way?
FeedItem.vue
methods: {
savePost(Post) {
this.$store.commit('savedPosts/addItem', Post)
},
deletePost(Post) {
this.$store.commit('savedPosts/removeItem', Post)
}
}
Store
export const state = () => ({
items: [
],
})
export const mutations = {
updateItemsOnLoad(state, array) {
var oldItems = state.items
var newItems = array.flat()
var joinedItems = newItems.concat(oldItems);
state.items = joinedItems.flat()
},
addItem(state, item) {
state.items.push(item)
this.$warehouse.set('savedPosts', state.items)
},
removeItem(state, item) {
var index = state.items.findIndex(c => c.id == item.id);
state.items.splice(index, 1);
this.$warehouse.set('savedPosts', state.items)
},
}
So my main question: Is there a more efficient way to check whether a post exists within the items array without querying it on every feed item?

(Vue 3) Error: AG Grid: cannot get grid to draw rows when it is in the middle of drawing rows

-- Initial setup --
Create component
const ButtonAgGrid= {
template: "<button>{{ displayValue }}</button>",
setup(props) {
const displayValue = 'TEST-TEXT';
return {
displayValue,
};
},
};
Register component
<AgGridVue
:components="{
ButtonAgGrid
}"
...
/>
Pass data
const columnDefs = [
{
field: "name"
},
{
field: "button",
cellRenderer: "ButtonAgGrid",
}
]
const rowData = computed(() => {
return {
name: testReactiveValue.value ? 'test', 'test2'
}
})
And when computed "rowData" updated, agGrid send error:
Error: AG Grid: cannot get grid to draw rows when it is in the middle of drawing rows. Your code probably called a grid API method while the grid was in the render stage. To overcome this, put the API call into a timeout, e.g. instead of api.redrawRows(), call setTimeout(function() { api.redrawRows(); }, 0). To see what part of your code that caused the refresh check this stacktrace.
But if we remove cellRenderer: "ButtonAgGrid", all work good
My solution is to manually update rowData.
watchEffect(() => {
gridApi.value?.setRowData(props.rowData);
});
This one works well, but I wish it was originally

How to update data after ajax reload using initComplete callback for DataTables when using ajax source data?

I’m using a select object to trigger an ajax reload for a DataTable.
I need to add individual column searching with select inputs for a given column (not for every column) but the select is filled with the previous ajax response.
How can I update the data that the initCompleteFunction callback uses to fill the select input in the individual column searching?
// this is the select that triggers the ajax.reload
$('#proveedor').on('change', function () {
$datatable
.DataTable()
.ajax
.reload(initCompleteFunction, false);
});
// this is my initCompleteFunction callback
function initCompleteFunction(settings, json){
var api = new $.fn.dataTable.Api( settings );
api.columns().every( function () {
var column = this;
if ($(column.header()).hasClass('select')) {
var select = $('<select><option value="">' + $(column.header()).html() + '</option></select>')
.appendTo( $(column.footer()).empty() )
.on( 'change', function () {
var val = $.fn.dataTable.util.escapeRegex(
$(this).val()
);
column
.search( val ? '^'+val+'$' : '', true, false )
.draw();
return false;
} );
//this is the part that keeps previous data insted of the new one from the ajax reload
column.data().unique().sort().each( function ( d, j ) {
select.append( '<option value="'+d+'">'+d+'</option>' );
} );
}
});
}
// and this is how I’m setting the DataTable
var $datatable = $('#table_materiales');
$datatable
.on('xhr.dt', function ( e, settings, json, xhr ) {
initCompleteFunction(settings, json);
})
.DataTable({
"ajax": {
"url": "http://my_endpoint",
"dataSrc": "",
"type": "POST",
"data": {
id_proveedor: function () {
return $('#proveedor').val(); // to get the value in the provider’s filter (select)
}
}
},
"columns": [
{
data: 'row_num'
},{
className: "select",
data: 'material'
},
// here goes the rest of the column definitions
],
"paging": false,
'columnDefs': [
{
'targets': 0,
'checkboxes': {
'selectRow': true
}
}
],
'select': {
'style': 'multi'
},
'order': [
[3, 'asc']
],
"createdRow": function (row, data, dataIndex) {
$(row).attr('data-id-material', data.id_material);
$(row).attr('data-pedido_sugerido', data.pedido_sugerido);
$(row).attr('id', 'id_' + data.row_num);
if(data['status_de_tiempo']=='FUERA'){
$(row).addClass('redClass');
}
},
});
During research I found that the xhr.dt event is triggered before the ajax.reload() is completed so the data keeps outdated when the select for the individual column search is populated. See this reference
User grozni posted this on April, 2019:
I have used console logs and was able to confirm that the event fires before the XHR event concludes, and does not pull the latest JSON. I used XHR tracking where I could to get around it but it's still really inconvenient and complicating matters alot. I need to be able to do certain things after the data is loaded and drawn. Perhaps it's worthy of a bug report
I found this post (See here) where user conangithub needed to
count DataTables item after I reload DataTable successfully
User lovecoding-git suggested this approach:
table= $('#example').DataTable();
$('#example').on('draw.dt', function() {
console.log(table.ajax.json().recordsTotal);
});
So, for my own issue, instead of
.on('xhr.dt', function ( e, settings, json, xhr ) {
initCompleteFunction(settings, json);
})
I wrote
.on('draw.dt', function ( e, settings, json, xhr ) {
initCompleteFunction(settings, json);
})
Et voilà.
I got the needed solution.

I have event duplication after action was moved in store object

In my laravel 5.8 / vue 2.5.17 / vuex^3.1.0 I have a problem that with dialog opened I have event duplication.
I have an event for item deletion :
In my vue file:
...
mounted() {
bus.$on('dialog_confirmed', (paramsArray) => {
if (paramsArray.key == this.deleteFromUserListsKey(paramsArray.user_list_id)) {
this.runDeleteFromUserLists(paramsArray.user_list_id, paramsArray.index);
}
})
bus.$on('onUserListDeleteSuccess', (response) => {
this.is_page_updating = false
this.showPopupMessage("User lists", 'User\'s list was successfully deleted!', 'success');
})
bus.$on('onUserListDeleteFailure', (error) => {
this.$setLaravelValidationErrorsFromResponse(error.message);
this.is_page_updating = false
this.showRunTimeError(error, this);
this.showPopupMessage("User lists", 'Error adding user\'s list !', 'error');
})
}, // mounted() {
methods: {
confirmDeleteUserList(user_list_id, user_list_title, index) {
this.confirmMsg("Do you want to exclude '" + user_list_title + "' user list ?", {
key: this.deleteFromUserListsKey(user_list_id), user_list_id: user_list_id, index: index
}, 'Confirm', bus);
}, //confirmDeleteUserList(id, user_list_title, index) {
deleteFromUserListsKey(user_list_id) {
return 'user_list__remove_' + user_list_id;
},
runDeleteFromUserLists(user_list_id, index) {
this.$store.dispatch('userListDelete', { logged_user_id : this.currentLoggedUser.id, user_list_id : user_list_id } );
}, // runDeleteFromUserLists() {
and in resources/js/store.js :
state : {
...
userLists: [],
...
actions : {
userListDelete(context, paramsArray ) {
axios({
method: ( 'delete' ),
url: this.getters.apiUrl + '/personal/user-lists/' + paramsArray.user_list_id,
}).then((response) => {
let L = this.getters.userLists.length
for (var I = 0; I < L; I++) {
if (response.data.id == this.getters.userLists[I].id) {
this.getters.userLists.splice(this.getters.userLists.indexOf(this.getters.userLists[I]), 1)
context.commit('refreshUserLists', this.getters.userLists);
break;
}
}
bus.$emit( 'onUserListDeleteSuccess', response );
}).catch((error) => {
bus.$emit('onUserListDeleteFailure', error);
});
}, // userListDelete(context, paramsArray ) {
confirmMsg (based on https://github.com/euvl/vue-js-modal )is defined in my mixing :
confirmMsg: function (question, paramsArray, title, bus) {
this.$modal.show('dialog', {
title: title,
text: question,
buttons: [
{
title: 'Yes',
default: true, // Will be triggered by default if 'Enter' pressed.
handler: () => {
bus.$emit('dialog_confirmed', paramsArray);
this.$modal.hide('dialog')
}
},
{
title: '', // Button title
handler: () => {
} // Button click handler
},
{
title: 'Cancel'
}
]
})
},
it worked ok, until I moved userListDelete method from my vue file into store.js.
As a result on 1st event item is deleted ok, the the second item raise error that item was not found and I do not know event is doubled...
How to fix it ?
UPDATED BLOCK :
I still search for valid decision :
I uploaded live demo at :
http://178.128.145.48/login
demo#demo.com wdemo
http://178.128.145.48/websites-blogs will be opened.
Please, try to go to “User's lists” by link at top left menu https://prnt.sc/nq4qiy
and back several times. When on “User's lists” page I try to delete 1 user list it is deleted, but I got several messages
and url in “network” section of my browser : https://imgur.com/a/4ubFB0g
Looks like events are duplicated. And looks like that is move between pages number of guplications is raised.
Why and how to fix it ?
I use #click.prevent in triggering the event to show confirm delete message.
There is “ Add Demo Data” to add more demo rows.
Thanks!
Well, it is quite obvious.
Take a closer look at the Vue component lifecycle diagram.
Your component is mounted each time you enter a route.
So, bus.$on inside your mounted block executed each time you enter this route.
I suggest you move bus event handlers to some other location. For example app.js/ App.vue mounted hook or directly into the store. Since all you do inside handler is calling store actions.

Ember.js - Reload paginated list from API after model deletion (and probably insertion)

I have a paginated list of models which comes from my REST api.
I use the api's pagination metadata to get the total number of records from my DB, and see if there are previous or next pages.
If I delete one of the records on the current page, I would like several things to happen:
- The first record of the next page should appear in the current page (if it exists).
- My metadata to be updated. (Total and pagination data)
The direct transitionToRoute method on the controller is not doing any of that. I believe an API reload of the current page is the way to go, but it doesn't seem implemented as far as I know.
I have managed to get the result I want by doing self.transitionToRoute('index') followed by another self.transitionToRoute to the page I want reloaded... This is downright horrible and makes me cringe. There must be a better way!
Here is some of the relevant code:
//router.js
App.Router.map(function(){
this.resource('jobs', function(){
this.resource('job', { path:'/:job_id' }, function(){
this.route('edit');
});
this.route('create');
});
});
//mixins.js
App.PaginatedListController = Ember.Mixin.create({
queryParams: ['page'],
page: 1,
total: function(){
return this.get('meta').count;
}.property('meta'),
previousAPIPage: function(){
return this.get('meta').previous;
}.property('meta'),
nextAPIPage: function(){
return this.get('meta').next;
}.property('meta'),
hasPreviousPage: function(){
return this.get('previousAPIPage') ? true : false;
}.property('previousAPIPage'),
hasNextPage: function(){
return this.get('nextAPIPage') ? true : false;
}.property('nextAPIPage'),
actions:{
previousPage: function(){
this.decrementProperty('page');
this.transitionToRoute({
queryParams: {
page: this.get('page')
}
});
},
nextPage: function(){
this.incrementProperty('page');
this.transitionToRoute({
queryParams: {
page: this.get('page')
}
});
},
},
});
//controllers\jobController.js
App.JobsController = Ember.ArrayController.extend(App.PaginatedListController, {
sortProperties: ['name'],
sortAscending: true,
meta: function(){
return this.store.metadataFor('job');
}.property('model.#each')
});
App.JobController = Ember.ObjectController.extend({
needs: ['jobs'],
deleteMode: false,
actions: {
delete: function(){
// our delete method now only toggles deleteMode's value
this.toggleProperty('deleteMode');
},
cancelDelete: function(){
// set deleteMode back to false
this.set('deleteMode', false);
},
confirmDelete: function(){
var self = this;
this.set('deleteMode', false);
this.get('model').destroyRecord().then(function(response) {
var qParams = self.get('controllers.jobs').get('queryParams');
//This is where it hurts
self.transitionToRoute('index');
//This is what I want reloaded
self.transitionToRoute('jobs', {queryParams:qParams});
});
},
}
});