Vue3-My provide is not updated after changing the data using mounted - vue.js

I tried to provide my data from a parent element like below.
data(){
return{
allData:null,
ingCollection:null,
selectedDish:[]
}
},
mounted(){
Promise.all([
d3.json('data.json'),
d3.json('ingredientsonly.json')
]).then((data)=>{
this.allData=data[0];
this.ingCollection=data[1];
})
},
components:{sidePanel,centerPiece},
methods: {
// receiveIngredients(selected){
// let selections = this.allData.filter(d=>{
// d.ingredients.includes(selected)
// });
// }
},
provide() {
return{
allData:this.allData,
ingCollection:this.ingCollection,
selectedDish:this.selectedDish,
receiveIngredients:this.receiveIngredients
}
}
However, after mounted lifecycle hook was run,
data is updated while provide elements were not updated.
Why is it?
Thank you

provide() is only called once at initialization, and not when there's a change to the references within.
Instead, you can provide an object (e.g., named root), and then update a property of that object in mounted():
export default {
provide() {
return {
root: {
allData: null,
ingCollection: null,
}
}
},
mounted() {
Promise.all([
d3.json('data.json'),
d3.json('ingredientsonly.json')
]).then((data)=>{
this.root.allData = data[0];
this.root.ingCollection = data[1];
})
}
}

Related

Start watcher after created() is done

My goal is to initially set up a data property when component is created and then set up a watcher on this property. The issue I am struggling with is the watcher catches initial property change in created method but this is not what I want. I would rather to watch data property only after initial change is made in created().
export default {
name: 'testComponent',
data() {
return {
testValue: 1;
}
},
watch: {
testValue() {
console.log('watcher catches!');
},
created() {
console.log(this.testValue);
this.testValue = 2;
console.log(this.testValue);
}
}
// CONSOLE OUTPUT: 1 -> watcher catches! -> 2
Can you tell me how to achieve behaviour like that?
No idea why you'd want that but you could simply do it like this:
export default {
name: 'testComponent',
data() {
return {
ready: false,
testValue: 1
}
},
watch: {
testValue() {
if (!this.ready) return;
console.log('watcher catches!');
},
created() {
this.testValue = 2;
this.ready = true;
}
}

Vue3: how to pass an object from provide to index

I've been using vue.js for a few weeks and I would like to understand how to globally inject to child components an object coming from the server.
When I try to inject the object using inject:['user'] to a child component it returns an empty object.
data() {
return {
user: []
}
},
methods: {
getLoggedUserData() {
axios.get('/api/get-user/' + window.auth.id
).then(response => {
this.user = response.data.user;
});
}
},
provide: {
return {
user: this.user
}
},
created() {
this.getLoggedUserData();
}
The provide option should be a function in this case to get access to this.user property:
export default {
provide() {
return {
user: this.user
}
}
}
For descendants to observe any changes to the provided user, the parent must only update user by subproperty assignment (e.g., this.user.foo = true) or by Object.assign() (e.g., Object.assign(this.user, newUserObject)):
export default {
methods: {
async getLoggedUserData() {
const { data: user } = await axios.get('https://jsonplaceholder.typicode.com/users/1')
// ❌ Don't do direct assignment, which would overwrite the provided `user` reference that descendants currently have a hold of:
//this.user = user
Object.assign(this.user, user) ✅
}
}
}
demo

How to full state before going throw script in component vue

Mey be it is simple, but I'm new in frontend. I have a page component. And I need to fetch data before component calculated.
import {mapActions, mapGetters} from 'vuex'
export default {
name: "notFoundPage",
methods: {
...mapActions([
'GET_SUBCATEGORIES_FROM_CATEGORIES'
]),
},
computed: {
...mapGetters([
'SUBCATEGORIES'
]),
subCategories() {
// doing some calculations with already updated SUBCATEGORIES in store
}
return result;
}
},
created() {
this.GET_SUBCATEGORIES_FROM_CATEGORIES()
> **// from here we go to store**
},
mounted() {
this.GET_SUBCATEGORIES_FROM_CATEGORIES()
}
}
store:
let store = new Vuex.Store({
state: {
categories: [],
subcategories: []
},
mutations: {
SET_CATEGORIES_TO_STATE: (state, categories) => {
state.categories = categories;
},
SET_SUBCATEGORIES_TO_STATE: (state, subcategories) => {
state.subcategories = subcategories;
}
},
actions: {
GET_CATEGORIES_FROM_API({commit}) {
return axios('http://localhost:3000/categories',
{
method: "GET"
})
But here compiler returns to component. I do not have any idea, why it is not finishing this action. And after calculating the computed block in component it returns to this point. But I need 'SET_CATEGORIES_TO_STATE' already updated
.then((categories) => {
commit('SET_CATEGORIES_TO_STATE', categories.data)
return categories;
}).catch((error) => {
console.log(error);
return error;
})
},
GET_SUBCATEGORIES_FROM_CATEGORIES({commit}) {
this.dispatch('GET_CATEGORIES_FROM_API').then(categories => {
let subs = categories.data.map(function(category) {
return category.subcategories.map(function(subcategory) {
return subcategory.name
})
})
commit('SET_SUBCATEGORIES_TO_STATE', subs)
return subs
})
}
},
getters: {
CATEGORIES(state) {
return state.categories;
},
SUBCATEGORIES(state) {
return state.subcategories;
}
}
if you have difficulties with timings and async tasks, why don't you use async/await?
you want to wait in a async function (for example calling a backend for data) till the data is fetched. then you want to manipulate/delete/change/add, do what ever you want with that data and display the result on screen.
the point is, Vue is a reactive Framework, which means it rerenders (if the setup is correct made) the content by itself after what ever calculation is finished. so don't worry about something like that.
to be honest, the question is asked really weird. and your code is hard to read. sometimes moving two steps back and try a other way isn't false as well.

VueJS How to access Mounted() variables in Methods

I'm new in Vue and would like assistance on how to access and use variables created in Mounted() in my methods.
I have this code
Template
<select class="controls" #change="getCatval()">
Script
mounted() {
var allcards = this.$refs.allcards;
var mixer = mixitup(allcards);
},
methods: {
getCatval() {
var category = event.target.value;
// I want to access mixer here;
}
}
I can't find a solution anywhere besides this example where I could call a method x from mounted() and pass mixer to it then use it inside my getCatval()
Is there an easier way to access those variables?
I will first suggest you to stop using var, and use the latest, let and const to declare variable
You have to first declare a variable in data():
data(){
return {
allcards: "",
mixer: ""
}
}
and then in your mounted():
mounted() {
this.allcards = this.$refs.allcards;
this.mixer = mixitup(this.allcards);
},
methods: {
getCatval() {
let category = event.target.value;
this.mixer
}
}
like Ninth Autumn said : object returned by the data function and props of your components are defined as attributes of the component, like your methods defined in the method attribute of a component, it's in this so you can use it everywhere in your component !
Here an example:
data() {
return {
yourVar: 'hello',
};
},
mounted() { this.sayHello(); },
method: {
sayHello() { console.log(this.yourVar); },
},
Update
you cannot pass any value outside if it's in block scope - Either you need to get it from a common place or set any common value
As I can see, var mixer = mixitup(allcards); is in the end acting as a function which does some operation with allcards passed to it and then returns a value.
1 - Place it to different helper file if mixitup is totally independent and not using any vue props used by your component
In your helper.js
const mixitup = cards => {
// Do some operation with cards
let modifiedCards = 'Hey I get returned by your function'
return modifiedCards
}
export default {
mixitup
}
And then in your vue file just import it and use it is as a method.
In yourVue.vue
import Helpers from '...path../helpers'
const mixitup = Helpers.mixitup
export default {
name: 'YourVue',
data: ...,
computed: ...,
mounted() {
const mixer = mixitup(allcards)
},
methods: {
mixitup, // this will make it as `vue` method and accessible through
this
getCatval() {
var category = event.target.value;
this.mixitup(allcards)
}
}
}
2- Use it as mixins if your mixitup dependent to your vue and have access to vue properties
In your yourVueMixins.js:
export default {
methods: {
mixitup(cards) {
// Do some operation with cards
let modifiedCards = 'Hey I get returned by your function'
return modifiedCards
}
}
}
And import it in your vue file:
import YourVueMixins from '...mixins../YourVueMixins'
const mixitup = Helpers.mixitup
export default {
name: 'YourVue',
mixins: [YourVueMixins] // this will have that function as vue property
data: ...,
computed: ...,
mounted() {
const mixer = this.mixitup(allcards)
},
methods: {
getCatval() {
var category = event.target.value;
this.mixitup(allcards)
}
}
}

vuejs2: how can i destroy a watcher?

How can i destroy this watcher? I need it only one time in my child component, when my async data has loaded from the parent component.
export default {
...
watch: {
data: function(){
this.sortBy();
},
},
...
}
gregor ;)
If you construct a watcher dynamically by calling vm.$watch function, it returns a function that may be called at a later point in time to disable (remove) that particular watcher.
Don't put the watcher statically in the component, as in your code, but do something like:
created() {
var unwatch = this.$watch(....)
// now the watcher is watching and you can disable it
// by calling unwatch() somewhere else;
// you can store the unwatch function to a variable in the data
// or whatever suits you best
}
More thorough explanation may be found from here: https://codingexplained.com/coding/front-end/vue-js/adding-removing-watchers-dynamically
Here is an example:
<script>
export default {
data() {
return {
employee: {
teams: []
},
employeeTeamsWatcher: null,
};
},
created() {
this.employeeTeamsWatcher = this.$watch('employee.teams', (newVal, oldVal) => {
this.setActiveTeamTabName();
});
},
methods: {
setActiveTeamTabName() {
if (this.employee.teams.length) {
// once you got your desired condition satisfied then unwatch by calling:
this.employeeTeamsWatcher();
}
},
},
};
</script>
If you are using vue2 using the composition-api plugin or vue3, you can use WatchStopHandle which is returned by watch e.g.:
const x = ref(0);
setInterval(() => {
x.value++;
}, 1000);
const unwatch = watch(
() => x.value,
() => {
console.log(x.value);
x.value++;
// stop watch:
if (x.value > 3) unwatch();
}
);
For this kind of stuff, you can investigate the type declaration of the API, which is very helpful, just hover the mouse on it, and it will show you a hint about what you can do: