Vue js watch object with debounce - vuejs2

I have data object localFilter inside component having 3 props and what i need is to watch for any props get changed inside this object and debounce in 1 second.
If i had one property the code below works, but what's the best way when i need whole object watcher with debounce?
export default {
name: "my-search",
data: () => ({
localFilter: null
}),
props: {
value: {
type: Object,
required: true
}
},
watch: {
'localFilter.searchText': _.debounce(function() {
console.log(this.localFilter);
this.$emit("input", Object.assign({}, this.localFilter));
}, 1000)

You can deep watch an object:
watch: {
// any prop or data or $props or $data
$props: {
deep: true,
handler: _.debounce( /*...*/)
},
}

Related

The prop object's property is undefined in refresh function

I use Vue.js and have a component. I pass a prop "request" to that component:
<adjustments-list
v-if="request"
:request="request"
/>
In the component I'm able to do this:
<text-input
:value="request.id"
/>
It works that is the value of "id" is displayed.
In props section of component:
props: {
request: Object
In mounted hook of component:
async mounted () {
await this.refresh()
},
In refresh function of component:
async refresh () {
console.log('this.request.id =', this.request.id)
if (this.request.id) {
const data = await requestApi.getRequestResultAdjustmentByReqId(this.request.id)
}
},
The this.request.id is undefined.
I'm not sure why.
If the request property is asynchronously available to the component then, you have to use combination of watchers like:
// adjustments-list component
new Vue({
props: {
request: Object
},
data() {
return {
apiData: null
}
},
watch: {
request(newValue, _oldValue) {
this.refresh(newValue);
}
},
mounted: function () {
// Do something here
},
methods: {
refresh (request) {
if (request.id) {
// Using promise instead of async-await
requestApi.getRequestResultAdjustmentByReqId(request.id)
.then(() => this.apiData = data);
}
}
}
});
Also, note that, mounted should be a plain old JS function and not an async function. That's the lifecycle method of the component supposed to behave in particular way.

How can I access a getter from a namespaced module with vuex?

My module has:
export default {
namespaced: true,
state: {
conversations: false
},
getters: {
getConversation(state, ConversationId) {
console.log('here i am!')
let conversation = _.find(state.conversations, { id: ConversationId })
console.log('conversation', conversation)
return conversation
},
In my component, I'm trying:
export default {
name: "ConversationDetail",
components: { HeaderSection },
computed: {
...mapGetters("conversation", ["getConversation"]),
ConversationId() {
return this.$route.params.ConversationId;
},
conversation() {
return this.getConversation(this.ConversationId);
}
},
methods: {
...mapActions("conversation", ["loadConversation"])
},
mounted() {
this.loadConversation(this.ConversationId);
But am getting an error:
Error in render: "TypeError: this.getConversation is not a function"
What am I doing wrong?
You are referencing the getter correctly, however, if you wish to pass parameters to your getter it needs to return a function that takes your parameter, for example with a curried lambda:
getter: (state) => (ConversationId) => {...}

Vue: object has changed twice in father component but only triggered `deep watch` once in child component

I have nested components in my project: and I want to communciate between two components through an array object activeGiftList
Father component view:
<div
id="giftContainer"
class="giftList"
#click="hideBoard"
>
<template
v-for="(item, index) in activeGiftList"
>
<send-gift-message
v-if="item"
:key="item.giftId"
:gift-item="item"
:gift-index="index"
#changeActiveGiftList="changeActiveGiftList"/>
</template>
</div>
Father component js:
watch: {
activeGiftList: {
handler: function (n) {
if (n) {
console.log('father: watch obj', n)
}
},
deep: true
}
}
Children component:
props: {
giftItem: {
type: Object,
default: () => {
return {}
}
},
giftIndex: {
type: Number,
default: 0
}
},
data () {
return { flag: false }
},
watch: {
giftItem: {
handler: function (val, oldVal) {
if (val) {
this.flag = true
console.log('child: watch obj', val)
}
},
immediate: true,
deep: true
}
},
created () {
console.log(this.flag, 'step 1')
},
mounted () {
console.log(this.flag, 'step 2')
setTimeout(() => {
console.log(this.flag, 'step 3')
}, 500)
},
I have changed this.activeGiftList twice:
first: [] => [{...}] // changed by posting a request
second: [{...}] => // use find methods of array to pick up the target object and add one more properties on it,then use $set to cover original object via the same index
here is console.log result:
father: watch obj, [{...}]
child: watch obj, {...}
false, step 1
false, step 2
father: watch obj, [{...}] // add one property on it.
true, step 3
I'm quite confused even if I have used deep in vue watcher, and using this.$set(this.activeGiftList, 0, newObj) to cover original object in array to trigger secont change, but still can't watch the second change in children component. And can't get changes from new property in child component DOM.
Also I have tried change exist property of the same object, and child component seems changing the same times as the father component,Is there any good ideas to help me solve this problem?

How to call a function when store has data

I have to create a video player object but I need the stream object to be present before I create the video player.
The this.stream is populated by vuex data store. but I find the mounted() and created() methods don't wait for store data to be present.
Here is the Player.vue component:
import Clappr from 'clappr';
import { mapActions, mapGetters } from 'vuex';
import * as types from '../store/types';
export default {
name: 'streams',
data() {
return {
player: null
};
},
computed: {
...mapGetters({
stream: types.STREAMS_RESULTS_STREAM
}),
stream() {
return this.$store.stream;
}
},
methods: {
...mapActions({
getStream: types.STREAMS_GET_STREAM
})
},
mounted() {
this.getStream.call(this, {
category: this.$route.params.category,
slug: this.$route.params.slug
})
.then(() => {
this.player = new Clappr.Player({
source: this.stream.url,
parentId: '#player',
poster: this.stream.poster,
autoPlay: true,
persistConfig: false,
mediacontrol: {
seekbar: '#0888A0',
buttons: '#C4D1DD'
}
});
});
}
};
Is there a way to wait for this.stream to be present?
You can subscribe on mutation event, For example if you have a mutation in your store called setStream you should subscribe for this mutation. Here's a code snippet of how to subscribe in mounted method.
mounted: function () {
this.$store.subscribe((mutation) => {
if (mutation.type === 'setStream') {
// Your player implementation should be here.
}
})
}

VueJS - Accessing store data inside mounted

I'm having trouble understanding the following:
I have a store which contains variables needed for the application. In particular, there is a globalCompanies which stores:
globalCompanies: {
current: [],
all: [],
currentName: "",
}
Inside another component, I want to do the following:
mounted() {
this.$store.dispatch( "fetchUsers" );
var currentName = this.$store.state.globalCompanies.currentName;
console.log(currentName);
},
However, this just shows as empty. I know the value is there because I have computed which returns the currentName and it works fine inside the view itself. It just doesn't like the fact that it's in the mounted component.
Where am I going wrong and what can I do to resolve this issue? I really need to capture the companies Name in order to use it for some real time events.
As a result of our discussion:
In the question Vuex state value, accessed in component's mounted hook, returns empty value, because it is set in an async action which does not resolve before mounted executes.
When you need to trigger some function when async action in Vuex resolves with a value, you can achieve it using watch on a computed property, which returns a value from your Vuex state. When a value in store changes, the computed property reflects these changes and watch listener executes:
const store = new Vuex.Store({
state: {
globalCompanies: {
test: null
}
},
mutations: {
setMe: (state, payload) => {
state.globalCompanies.test = payload
}
},
actions: {
pretendFetch: ({commit}) => {
setTimeout(() => {
commit('setMe', 'My text is here!')
}, 300)
}
}
})
new Vue({
el: '#app',
store,
computed: {
cp: function() { // computed property will be updated when async call resolves
return this.$store.state.globalCompanies.test;
}
},
watch: { // watch changes here
cp: function(newValue, oldValue) {
// apply your logic here, e.g. invoke your listener function
console.log('was: ', oldValue, ' now: ', newValue)
}
},
mounted() {
this.$store.dispatch('pretendFetch');
// console.log(this.cp, this.$store.state.globalCompanies.test); // null
// var cn = this.$store.state.globalCompanies.test; // null
// console.log(cn) // null
}
})
<script src="https://cdnjs.cloudflare.com/ajax/libs/vue/2.3.0/vue.js"></script>
<script src="https://unpkg.com/vuex#2.3.1"></script>
<div id="app">
{{ cp }}
</div>
VueJS - Accessing Store Data Inside Mounted
Ran into this issue and it turned out to be a scope issue.
Store:
export default () => {
items:[],
globalCompanies:{
current:[],
all:[],
currentName: "Something"
},
ok: "Here you go"
}
Getters:
export default {
getGlobalCompanies(state){
return state.globalCompanies;
}
}
Mounted: This works...
mounted() {
// Initialize inside mounted to ensure store is within scope
const { getters } = this.$store;
const thisWorks = () => {
const globalCompanies = getters.getGlobalCompanies;
}
},
This is Bad: Reaching for the store outside the mounted scope
mounted() {
function ThisDontWork() {
const { getters } = this.$store; // this.$store == undefined
}
ThisDontWork();
},