Using array.sort() on Vue data() variable - javascript

I'm loading Api data into a reactive variable called 'MyListings', and attempting to sort it based on latest id -> earliest id.
The problem I'm having is that since array.sort is an 'in-place' function it overwrites the original array which causes the Vue page to infinitely re-render.
Is there some way to clone the data out of data()? (I tried setting a constant to this.MyListings which produced the same results as the original)
api data
[
{
id: 1,
title: "sdf",
start_date: "2021-01-13",
poster:
"http://localhost:8000/media/images/2-Artwork-by-Tishk-Barzanji_iZookmb.jpg",
genre: "Action"
},
{
id: 3,
title: "ooga booga",
start_date: "2021-01-07",
poster: "http://localhost:8000/media/images/1_bdm0Lld.jpg",
genre: "Thriller"
}
];
Relevant Vue bits
updated() {
this.sortedArray();
},
data() {
return {
genre: "",
MyListings: []
};
},
methods: {
// no access to AsnycData in components, handle the incoming data like axios in vanilla vue.
memberListings($axios) {
this.$axios
.get("/api/v1/memberlistings/")
.then(response => {
// console.log(response, "response");
this.MyListings = response.data;
})
.catch(error => {
console.log(error);
});
},
formSubmit() {
this.update(); //all dropdown combinations below include a POST request
},
update() {
if (this.genre !== "") {
console.log("genre submitted");
this.$axios
.get(`/api/v1/memberlistings/`, {
params: {
genre: this.genre
}
})
.then(response => {
this.MyListings = response.data;
})
.catch(error => {
console.log(error);
});
} else {
this.$axios
.get(`/api/v1/memberlistings/`)
.then(response => {
this.MyListings = response.data;
})
.catch(error => {
console.log(error);
});
}
},
sortedArray() {
const sortedMyListings = this.MyListings;
sortedMyListings.sort((a, b) => b.id - a.id);
console.log(sortedMyListings, "sortedlist");
console.log("works");
}
}
**This is what the endless rendering looks like in console log **
[1]: https://i.stack.imgur.com/CTVAH.png

I believe, you want to display data in sorted order. hence, you should create a computed property.
computed:{
sortedData() {
return this.MyListings.map(item=>item).sort((a,b)=> a.id - b.id)
}
},
and use that computed property in template
<template>
<div id="app">
<div v-for="item in sortedData" :key="item.id">
{{item.id}}-{{item.title}}
</div>
</div>
</template>

Related

how to prevent a re-rendering of a variable that is not being used in the HTML of my vue.js component?

I am trying to recreate a real example of my code.
In my real code, this line is actually a component that will fetch an endpoint every few seconds, and fetch a random array of "n" length, myData it will contain these fetch.
<div v-for="item in addingData(myData)"> <!-- in My real code, "myData" should be the answer of an endpoint, is an setInterval, returns data like [{id:1},{id:2}] -->
{{ item.id }}
</div>
I am simulating that the response changes in myData with the help of setTimeOut
mounted() {
setTimeout(() => {
console.log('First data');
this.myData = [{ id: 3 }, { id: 2 }, { id: 1 }];
setTimeout(() => {
console.log('second data');
this.myData = [{ id: 4 }, { id: 4 }];
setTimeout(() => {
console.log('Third data');
this.myData = [];
}, 3000);
}, 3000);
}, 2000);
},
I am trying to make that every time I receive data in myData, the list of the concatenation of the received data is shown without having repeated data. That's why every time I receive data, that calls the function addingData(myData) that will do this data concatenation.
I'm using the function v-for="item in addingData(myData) and auxData is the variable that will do this concatenation.
why when there is new data, the addingData function is called 2 times and how can I prevent it?
in terms of performance this should be the output in the console.log:
what causes this re-rendering and how can I avoid it?
this is my live code:
https://stackblitz.com/edit/vue-l7gdpj?file=src%2FApp.vue
<template>
<div id="app">
<div v-for="item in addingData(myData)">
{{ item.id }}
</div>
</div>
</template>
<script>
import HelloWorld from './components/HelloWorld.vue';
export default {
name: 'App',
data() {
return {
myData: [],
auxData: [],
};
},
mounted() {
setTimeout(() => {
console.log('First data');
this.myData = [{ id: 3 }, { id: 2 }, { id: 1 }];
setTimeout(() => {
console.log('second data');
this.myData = [{ id: 4 }, { id: 4 }];
setTimeout(() => {
console.log('Third data');
this.myData = [];
}, 3000);
}, 3000);
}, 2000);
},
methods: {
addingData(getDataFetch) {
console.log('Entering AddingData', getDataFetch);
if (getDataFetch.length !== 0) {
if (this.auxData.length === 0) {
//Adding initial data
this.auxData = getDataFetch;
} else {
//prevent duplicated values
getDataFetch.forEach((item) => {
const isNewItem = this.auxData.find((itemAux) => {
return item.id === itemAux.id;
});
if (!isNewItem) {
//adding new data
this.auxData.unshift(item);
}
});
}
} else {
//if there is not data, return []
return this.auxData;
}
},
},
};
</script>
As per my understanding, You want to combined the unique objects in to an array getting from multiple API calls and show them into the template using v-for. If Yes, You can achieve that by using computed property.
As you are updating the myData every time you are getting response, You can push the unique objects into a separate array and then return that array using a computed property.
Live Demo :
new Vue({
el: '#app',
data: {
combinedData: [],
myData: []
},
mounted() {
setTimeout(() => {
console.log('First data');
this.myData = [{ id: 3 }, { id: 2 }, { id: 1 }];
this.pushData(this.myData)
setTimeout(() => {
console.log('second data');
this.myData = [{ id: 4 }, { id: 4 }];
this.pushData(this.myData)
setTimeout(() => {
console.log('Third data');
this.myData = [];
this.pushData(this.myData)
}, 3000);
}, 3000);
}, 2000);
},
methods: {
pushData(data) {
data.forEach(obj => {
if (!JSON.stringify(this.combinedData).includes(JSON.stringify(obj))) {
this.combinedData.push(obj)
}
});
}
},
computed: {
finalData() {
return this.combinedData
}
}
})
<script src="https://cdnjs.cloudflare.com/ajax/libs/vue/2.5.17/vue.js"></script>
<div id="app">
<div v-for="item in finalData">
{{ item.id }}
</div>
</div>
in terms of performance this should be the output in the console.log
In terms of performance, you should use as few reactive data as possible, especially if your object has many properties. I would modify auxData directly.
this.addingData([{ id: 3 }, { id: 2 }, { id: 1 }]);
Simplified addingData
addingData(getDataFetch) {
// It's faster to get the id-s first
let itemDict = new Set(this.auxData.map((m) => m.id));
getDataFetch.forEach((item) => {
if (!itemDict.has(item.id)) {
this.auxData.unshift(item);
itemDict.add(item.id);
}
});
},
And iterate over it
<div v-for="item in auxData">
{{ item.id }}
</div>
Also watching object list can also cause performance issues. It should be used on primitive values.
Example on StackBlitz
Looks like you should be using v-for with auxData as that's what you're updating using the result of your API call (myData). As your API sends you new results, use a watcher to run a function whenever a new update is made to then also update auxData
updated stackblitz
watch: {
myData(newData, oldData) {
console.log('Entering AddingData', newData);
if (newData.length !== 0) {
if (this.auxData.length === 0) {
this.auxData = newData;
} else {
newData.forEach((item) => {
const isNewItem = this.auxData.find((itemAux) => {
return item.id === itemAux.id;
});
if (!isNewItem) {
this.auxData.unshift(item);
}
});
}
}
},
},
<div v-for="item in auxData">
{{ item.id }}
</div>

How can I use data defined in data() in other methods in Vue js?

First I defined Types, Severities, and Statuses as [] and returned them in data().
Then I filled them with data in the methods getTypes(), getSeverities(), and getStatuses().
I want to use Types, Severities, and Statuses in the method getName()(just has console.log() as an example for now).
I noticed when debugging getNames(), type in the second for loop is undefined. Is it because the method is using Type before it was assigned values in getTypes()? How can I make it work?
Note: Types, Severities, and Statuses do get assigned values in the methods getTypes(), getSeverities(), and getStatuses(), the issues is how to use the data in other methods.
<script>
import IssuesTable from '../MyIssuesPage/IssuesTable.vue'
import AddIssue from '../MyIssuesPage/AddIssue.vue'
import axios from 'axios'
export default {
props: ['id', 'project', 'issuesList', 'index'],
components: { IssuesTable, AddIssue },
data() {
return {
Issues: this.issuesList[this.index],
tab: null,
items: [{ tab: 'Issues' }, { tab: 'Calender' }, { tab: 'About' }],
Types: [],
Severities: [],
Statuses: [],
}
},
setup() {
return {
headers: [
{ text: 'Title', value: 'title' },
{ text: 'Description', value: 'description' },
{ text: 'Estimate', value: 'time_estimate' },
{ text: 'Assignees', value: 'userid' },
{ text: 'Type', value: 'issueTypeId' },
{ text: 'Status', value: 'issueStatusId' },
{ text: 'Severity', value: 'issueSeverityId' },
],
}
},
mounted() {
this.getTypes(), this.getSeverities(), this.getStatuses(), this.getNames()
},
methods: {
getTypes() {
axios
.get('http://fadiserver.herokuapp.com/api/v1/my-types')
.then(response => {
this.Types = response.data
})
.catch(error => {
console.log(error)
})
},
getSeverities() {
axios
.get('http://fadiserver.herokuapp.com/api/v1/my-severities')
.then(response => {
this.Severities = response.data
})
.catch(error => {
console.log(error)
})
},
getStatuses() {
axios
.get('http://fadiserver.herokuapp.com/api/v1/my-status')
.then(response => {
this.Statuses = response.data
})
.catch(error => {
console.log(error)
})
},
getNames() {
for (var issue of this.Issues) {
for (var type of this.Types) {
if (issue.issueTypeId == type.id) console.log('test')
}
}
},
},
}
</script>
First of all, use created() instead of mounted() for calling methods that fetch data.
Next, you need to call getNames() only after all fetch methods complete.
created() {
this.getTypes()
.then(this.getSeverities())
.then(this.getStatuses())
.then(this.getNames());
}
In order to chain methods like this you need to put return statement before each axios like this
getTypes() {
return axios
.get("https://fadiserver.herokuapp.com/api/v1/my-types")
.then((response) => {
this.Types = response.data;
})
.catch((error) => {
console.log(error);
});
}
In this component, I see you are receiving issuesList and index props from the outside. I cannot know those values but you can console.log both of them inside created() and see what is happening because issuesList[index] is undefined.
That probably means issuesList is an array and that index does not exist in that array.

Vue, firestore: how to display LIVE data after merging collections

See EDIT Below
I have massively improved over my last question, but I am stuck again after some days of work.
Using Vue, Vue-router, Vuex and Vuetify with the Data on Googles Could Firestore
I want to update my data live, but i cannot find a way to do this.
Do i need to restructure, like moving products and categories into one collection?
Or is there any bind or query magic to get this done.
As you can see below, it loads the data on click quite well, but I need the live binding 'cause you could have the page open and someone could sell the last piece (amountLeft = 0). (And a lot of future ideas).
My data structure is the following:
categories: {
cat_food: {
name: 'Food'
parentCat: 'nC'
},
cat_drinks: {
name: 'Food'
parentCat: 'nC'
},
cat_beer: {
name: 'Beer'
parentCat: 'cat_drinks'
},
cat_spritz: {
name: 'Spritzer'
parentCat: 'cat_drinks'
},
}
products: {
prod_mara: {
name: 'Maracuja Spritzer'
price: 1.5
amountLeft: 9
cat: ['cat_spritz']
},
prod_capp: {
name: 'Cappuccino'
price: 2
cat: ['cat_drinks']
},
}
The categories and the products build a tree. The GIF shows me opening the categories down to show a product. You see that it's a product when you have a price tag.
You can see there are two categories that have the same parent (cat_drinks).
The product prod_capp is also assigned to the category and shown side by side to the categories.
I get the data currently this way:
catsOrProd.js
import { catsColl, productsColl } from '../firebase'
const state = {
catOrProducts: [],
}
const mutations = {
setCats(state, val) {
state.catOrProducts = val
}
}
const actions = {
// https://vuefire.vuejs.org/api/vuexfire.html#firestoreaction
async bindCatsWithProducts({ commit, dispatch }, CatID) {
if (CatID) {
// console.log('if CatID: ', CatID)
await Promise.all([
catsColl.where('parentCat', '==', CatID).orderBy('name', 'asc').get(),
productsColl.where('cats', 'array-contains', CatID).orderBy('name', 'asc').get()
])
.then(snap => dispatch('moveCatToArray', snap))
} else {
// console.log('else CatID: ', CatID)
await Promise.all([
catsColl.where('parentCat', '==', 'nC').orderBy('name', 'asc').get(),
productsColl.where('cats', 'array-contains', 'nC').orderBy('name', 'asc').get()
])
.then(snap => dispatch('moveCatToArray', snap))
}
},
async moveCatToArray({ commit }, snap) {
const catsArray = []
// console.log(snap)
await Promise.all([
snap[0].forEach(cat => {
catsArray.push({ id: cat.id, ...cat.data() })
}),
snap[1].forEach(cat => {
catsArray.push({ id: cat.id, ...cat.data() })
})
])
.then(() => commit('setCats', catsArray))
}
}
export default {
namespaced: true,
state,
actions,
mutations,
}
This is a part of my vue file that is showing the data on screen. I have left out the unnecessary parts.
To open everything a have a route with props and clicking on the category sends the router to the next category. (this way i can move back with browser functionality).
Sale.vue
<template>
...........
<v-col
v-for="catOrProduct in catOrProducts"
:key="catOrProduct.id"
#click.prevent="leftClickProd($event, catOrProduct)"
#contextmenu.prevent="rightClickProd($event, catOrProduct)">
....ViewMagic....
</v-col>
............
</template>
<script>
.........
props: {
catIdFromUrl: {
type: String,
default: undefined
}
},
computed: {
// https://stackoverflow.com/questions/40322404/vuejs-how-can-i-use-computed-property-with-v-for
...mapState('catOrProducts', ['catOrProducts']),
},
watch: {
'$route.path'() { this.bindCatsWithProducts(this.catIdFromUrl) },
},
mounted() {
this.bindCatsWithProducts(this.catIdFromUrl)
},
methods: {
leftClickProd(event, catOrProd) {
event.preventDefault()
if (typeof (catOrProd.parentCat) === 'string') { // when parentCat exists we have a Category entry
this.$router.push({ name: 'sale', params: { catIdFromUrl: catOrProd.id } })
// this.bindCatsWithProducts(catOrProd.id)
} else {
// ToDo: Replace with buying-routine
this.$refs.ProductMenu.open(catOrProd, event.clientX, event.clientY)
}
},
}
</script>
EDIT 24.09.2020
I have changed my binding logic to
const mutations = {
setCatProd(state, val) {
state.catOrProducts = val
},
}
const actions = {
async bindCatsWithProducts({ commit, dispatch }, CatID) {
const contain = CatID || 'nC'
const arr = []
catsColl.where('parentCat', '==', contain).orderBy('name', 'asc')
.onSnapshot(snap => {
snap.forEach(cat => {
arr.push({ id: cat.id, ...cat.data() })
})
})
productsColl.where('cats', 'array-contains', contain).orderBy('name', 'asc')
.onSnapshot(snap => {
snap.forEach(prod => {
arr.push({ id: prod.id, ...prod.data() })
})
})
commit('setCatProd', arr)
},
}
This works, as the data gets updated when I change something in the backend.
But now i get an object added everytime something changes. As example i've changed the price. Now i get this:
I don't know why, because i have the key field set in Vue. The code for the rendering is:
<v-container fluid>
<v-row
align="center"
justify="center"
>
<v-col
v-for="catOrProduct in catOrProducts"
:key="catOrProduct.id"
#click.prevent="leftClickProd($event, catOrProduct)"
#contextmenu.prevent="rightClickProd($event, catOrProduct)"
>
<div>
<TileCat
v-if="typeof(catOrProduct.parentCat) == 'string'"
:src="catOrProduct.pictureURL"
:name="catOrProduct.name"
/>
<TileProduct
v-if="catOrProduct.isSold"
:name="catOrProduct.name"
... other props...
/>
</div>
</v-col>
</v-row>
</v-container>
Why is this not updating correctly?
From the Vuefire docs, this is how you would subscribe to changes with Firebase only:
// get Firestore database instance
import firebase from 'firebase/app'
import 'firebase/firestore'
const db = firebase.initializeApp({ projectId: 'MY PROJECT ID' }).firestore()
new Vue({
// setup the reactive todos property
data: () => ({ todos: [] }),
created() {
// unsubscribe can be called to stop listening for changes
const unsubscribe = db.collection('todos').onSnapshot(ref => {
ref.docChanges().forEach(change => {
const { newIndex, oldIndex, doc, type } = change
if (type === 'added') {
this.todos.splice(newIndex, 0, doc.data())
// if we want to handle references we would do it here
} else if (type === 'modified') {
// remove the old one first
this.todos.splice(oldIndex, 1)
// if we want to handle references we would have to unsubscribe
// from old references' listeners and subscribe to the new ones
this.todos.splice(newIndex, 0, doc.data())
} else if (type === 'removed') {
this.todos.splice(oldIndex, 1)
// if we want to handle references we need to unsubscribe
// from old references
}
})
}, onErrorHandler)
},
})
I would generally avoid any unnecessary dependencies, but according to your objectives, you can use Vuefire to add another layer of abstraction, or as you said, doing some "magic binding".
import firebase from 'firebase/app'
import 'firebase/firestore'
const db = firebase.initializeApp({ projectId: 'MY PROJECT ID' }).firestore()
new Vue({
// setup the reactive todos property
data: () => ({ todos: [] }),
firestore: {
todos: db.collection('todos'),
},
})

vue.js component not updated after vuex action on another component

I've a component which render a booking table; When I update my store in another component, the table isn't updated (but the store does and so the computed properties; My guess is that the problem is related to the filter not being updated but I'm not sure at all.
To do so, I've a vuex store:
...
const store = new Vuex.Store({
state: {
bookings: [],
datesel: '',
},
getters: {
bookings: (state) => {
return state.bookings
},
},
mutations: {
SET_BOOKINGS: (state, bookings) => {
state.bookings = bookings
},
},
actions: {
setBookings: ({commit, state}, bookings) => {
commit('SET_BOOKINGS', bookings)
return state.bookings
},
}
})
export default store;
The table is basically a v-for with a filter:
<template v-for="booking in getBookings( heure, terrain )">
Where getBookings is a method:
getBookings(hour, court) {
return this.$store.state.bookings.filter(booking => booking.heure == hour && booking.terrain == court);
}
I've another component which will update my bookings state through a method:
bookCourt() {
axios.post('http://localhost/bdcbooking/public/api/reservations/ponctuelles',
{
date: this.datesel,
membre_id: '1',
heure: this.chosenHour,
terrain: this.chosenCourt,
saison_id: '1'
})
.then(response => {
// JSON responses are automatically parsed.
console.log(response.data);
})
.catch(e => {
this.errors.push(e)
})
axios.get('http://localhost/bdcbooking/public/api/getReservationsDate?datesel=' + this.datesel)
.then(response => {
// JSON responses are automatically parsed.
console.log(response.data);
this.bookings = response.data;
})
.catch(e => {
this.errors.push(e)
})
$(this.$refs.vuemodal).modal('hide');
}
While this.bookings is a computed property:
computed: {
bookings: {
get () {
return this.$store.getters.bookings
},
set (bookings) {
return this.$store.dispatch('setBookings', bookings)
console.log('on lance l action');
}
}
}
Your table is not updated because getBookings is a simple method and hence the method won't be fired again based on vuex state changes.
You can make this getBookings method as an computed property that returns filtered results and will also upadte on state changes.

Get Vue to update view/component

I'm stuck at a crossroads with a component I am working on.
I have the following component "RecentUpdates"
Within it I am passing props down to a few other components, as you can see from the top of the file.
My problem is when adding a new post, I can not figure out how to get the correct update object array back and i also can not figure out the correct 'Vue way' to update the data prop that is being passed down to the "PostList" component.
<template>
<div>
<PostFilter v-on:selectedCategory="getSelectedPosts" v-on:showAllPosts="showAllPosts" :user="user" :categories="categories"/>
<PostList v-if="recent_posts[0]" :categories="categories" :posts="recent_posts[0]" :user="user"/>
<Pagination v-on:getPreviousPage="getPreviousPage" v-on:getNextPage="getNextPage"/>
</div>
</template>
<script>
import PostList from './PostList';
import PostFilter from './PostFilter';
import Pagination from './Pagination';
import EventBus from '../event-bus';
export default {
name: 'RecentUpdates',
data: () => ({
errors: [],
recent_posts: [],
}),
props: ['categories', 'user'],
components: {
PostList,
PostFilter,
Pagination
},
created() {
if (this.user.meta.selected_categories[0] == 0) {
this.showAllPosts();
}
// do not call here, not working as expected
// is switching selected category to an incorrect one
// this.updateList();
this.getSelectedCategory();
},
watch: {
recent_posts: function(newValue) {
EventBus.$on('addPost', function(newPost) {
console.log(newPost);
this.$forceUpdate();
//this.recent_posts.push(newPost);
//this.$set(this.recent_posts, newPost, newPost);
// this.$nextTick(function () {
// this.recent_posts.push(newPost);
// });
});
console.log(this.recent_posts[0]);
// this.$nextTick(function () {
// console.log(this.recent_posts[0]) // => 'updated'
// });
// if (this.user.meta.selected_categories[0] == 0) {
// EventBus.$on('addPost', this.showAllPosts);
// } else {
// EventBus.$on('addPost', this.getSelectedCategory);
// }
//this.updateList();
}
},
methods: {
// updateList() {
// if (this.user.meta.selected_categories[0] == 0) {
// EventBus.$on('addPost', this.showAllPosts);
// //EventBus.$emit('newPost');
// } else {
// EventBus.$on('addPost', this.getSelectedCategory);
// //EventBus.$emit('newPost');
// }
// },
getSelectedCategory() {
let categoryId = this.user.meta.selected_categories[0];
this.getSelectedPosts(categoryId);
},
showAllPosts() {
axios.get('/wp-json/wp/v2/posts?_embed=true&status=[publish,resolved,unresolved]',
{headers: {'X-WP-Nonce': portal.nonce}})
.then(response => {
this.recent_posts = [];
//this.recent_posts = response.data;
//console.log(response.data);
this.recent_posts.push(response.data);
console.log(this.recent_posts[0]);
})
.catch(e => {
this.errors.push(e);
});
},
getSelectedPosts(categoryId) {
axios.get('/wp-json/wp/v2/posts?_embed=true&status=[publish,resolved,unresolved]&categories=' + categoryId,
{headers: {'X-WP-Nonce': portal.nonce}})
.then(response => {
this.recent_posts = [];
//console.log(response.data);
this.recent_posts.push(response.data);
console.log(this.recent_posts[0]);
})
.catch(e => {
this.errors.push(e);
});
},
/**
* Pagination methods
*
*/
getPreviousPage(page) {
axios.get('/wp-json/wp/v2/posts?_embed=true&status=[publish,resolved,unresolved]&page=' + page,
{headers: {'X-WP-Nonce': portal.nonce}})
.then(response => {
this.recent_posts = response.data;
})
.catch(e => {
this.errors.push(e);
});
},
getNextPage(page) {
axios.get('/wp-json/wp/v2/posts?_embed=true&status=[publish,resolved,unresolved]&page=' + page,
{headers: {'X-WP-Nonce': portal.nonce}})
.then(response => {
this.recent_posts = response.data;
})
.catch(e => {
this.errors.push(e);
});
}
},
}
</script>
<style>
</style>
So there are a number of issues I see reading through your code.
You have a recent_posts data property, which is an array. When you make your ajax call to get the posts you push the response which is also an array into the recent_posts array. Why? Why not just set recent_posts = response.data? Then you won't have to be passing recent_posts[0] around.
You're setting up your EventBus handler inside a watcher. This is really unusual. Typically you would set up a handler inside created or mounted.
this inside the EventBus handler likely refers to the EventBus and not your Vue. Ideally, you would set the handler to be a method on the component, which is already bound to the Vue. Something like EventBus.$on("addPost", this.addPost).
Once you've done all that, adding a new post should be as simple as this.recent_posts.push(newPost).
Here is what I might recommend.
export default {
name: 'RecentUpdates',
data(){
return {
errors: [],
recent_posts: []
}
},
props: ['categories', 'user'],
components: {
PostList,
PostFilter,
Pagination
},
created() {
if (this.user.meta.selected_categories[0] == 0) {
this.showAllPosts();
}
this.getSelectedCategory();
EventBus.$on("addPost", this.addPost)
},
beforeDestroy(){
EventBus.$off("addPost", this.addPost)
},
methods: {
getPosts(url){
axios.get(url, {headers: {'X-WP-Nonce': portal.nonce}})
.then(response => this.recent_posts = response.data)
.catch(e => this.errors.push(e))
},
showAllPosts() {
const url = '/wp-json/wp/v2/posts?_embed=true&status=[publish,resolved,unresolved]';
this.getPosts(url);
},
getSelectedPosts(categoryId) {
const url = '/wp-json/wp/v2/posts?_embed=true&status=[publish,resolved,unresolved]&categories=' + categoryId;
this.getPosts(url);
},
addPost(newPost){
this.recent_posts.push(newPost)
},
... //other methods
},
}
Try using kebab-case in your event listeners instead of camelCase:
Example: v-on:selectedCategory="getSelectedPosts" should be v-on:selected-category="getSelectedPosts".
Example: v-on:showAllPosts="showAllPosts" should be v-on:show-all-posts="showAllPosts" or even using the shortcut #show-all-posts="showAllPosts".
UPDATE: If you can provide the code of the other components so we can have a clearer vision of your problem, But you only want to track changes that happens on an object or an array in vue.js you need to deep watch them.
your watcher should be :
watch: {
recent_posts: {
deep: true,
handler: function( oldValue, newValue) {
console.log( "recent_posts has changed" );
// A post has been added, updated or even deleted
}
}
}

Categories