Vue vuex state watch is not working on first load - vue.js

I have below code to get new ID using watch. Its working fine. However, I need the function to get the ID on first load as well, which is not working. Is there anything I am missing in my code?
watch: {
id: {
immediate: true,
handler(newV, oldV) {
this.id = newV;
},
},
},
mounted () {
store.watch(store.getters.getId, id => {
this.id = id;
});
},
created() {
this.userID();
},
methods: {
userID () {
console.log('this.id);
}
}
}

You can just do this:
data() {
return {id: null}
}
watch: {
'$store.getters.getId': {
immediate: true,
handler: function(newV) {
this.id = newV
},
},
}
Using a computed property is better, as your component does not 'own the id'.
computed: {
id() {
return this.$store.getters.getId
},
},

Related

Using Created and Watcher in VUE.JS

I am using watch and created method for the same data.Is it duplicate code? Is there a better way to do it?
props: {
regionList: {
type: Array,
},
},
data() {
return {
regions: [],
};
},
watch: {
regionList() {
if (this.regionList) {
this.regions = this.regionList;
}
},
},
created() {
if (!this.regionList) {
this.getApi();
} else {
this.regions = this.regionList;
}
},
It is what immediate watcher is for:
watch: {
regionList: {
immediate: true,
handler(newVal) {
if (newVal.length) {
this.regions = newVal;
}
}
},
},
created() {
if (!this.regionList) {
this.getApi();
}
},

Get params of route Shopware 6

I try to extend the product detail page and get the productId out of the routes.
Shopware.Module.register('sw-product-content-element', {
routeMiddleware(next, currentRoute) {
if (currentRoute.name === 'sw.product.detail') {
currentRoute.children.push({
name: 'sw.product.detail.content-element',
path: '/sw/product/detail/:id/content-element',
component: 'sw-product-detail-content-element',
meta: {
parentPath: "sw.product.index"
},
props: {
default(route) {
console.log(route)
return {
productId: route.params.id
};
}
}
});
}
next(currentRoute);
}
});
I try to pass my productId as props to my component, but in my component productId is undefined.
Component.register('sw-product-detail-content-element', {
template,
props: {
productId: {
required: true,
type: String
},
},
data() {
return {
product: null
};
},
created() {
console.log(this.productId)
},
....
I found a solution. I do not need to pass my value as props, I can just use this.$route.params.id
Component.register('sw-product-detail-content-element', {
template,
props: {
productId: {
required: true,
type: String
},
},
data() {
return {
product: null
};
},
created() {
this.productId = this.$route.params.id
console.log(this.productId)
},
....

Child element not updating props after change in data coming from apollo in nuxt/vue

UPDATE: the main issue seems to be that the props only get updated once. They should change when this.campaign.name becomes available.
I want to dynamically update the title and breadcrumb data fields and show them on the page. Currently page page shows undefined or null. How can I fix this?
I tried to create a computed value but it only seems to update once (after head and breadcrumb data is already showed). A method does not work since I don't have anything to trigger the method.
What is the correct way to fix this?
I am using nuxt generate to deploy the app.
export default {
components: { PageHeader },
middleware: 'authenticated',
data() {
return {
title: 'Campaigns' + this.campaignName,
breadcrumb: [
{
text: 'Campaigns',
href: '/'
},
{
text: this.campaignName,
href: '/'
}
],
campaign: ''
}
},
apollo: {
campaign: {
prefetch: true,
query: campaignQuery,
variables() {
return { id: this.$route.params.id }
}
}
},
computed: {
campaignName() {
return this.campaign && this.campaign.name
}
},
head() {
return {
title: this.title
}
}
}
</script>
Your computed property campaignName returns undefined cuz this.campaign.name is not defined
campaignName() {
if(this.campaign && this.campaign.name) return "Campaigns" + this.campaign.name;
return "default value";
}
Then you can use it directly in head
head() {
return {
title: this.campaignName
}
}
The solution was putting the data elements directly as a computer property. (so no recalculation)
export default {
components: { PageHeader },
middleware: 'authenticated',
data() {
return {}
},
apollo: {
campaign: {
prefetch: true,
query: campaignQuery,
variables() {
return { id: this.$route.params.id }
}
}
},
computed: {
title() {
return this.campaign && `Campaign: ${this.campaign.name}`
},
breadcrumb() {
return [
{
text: 'Campaign',
href: '/'
},
{
text: this.campaign && this.campaign.name,
href: '/'
}
]
}
},
head() {
return {
title: this.title
}
}
}
</script>

Vue - using $emit, .sync pattern with not required props

If I have a non-required prop is it possible to emit (using $emit('update:<prop name>', value) ) it in the child component and have it update to the emitted value without the parent component having :<prop name>.sync="<data name>"
example child component:
Vue.component('child-component', {
props: {
bar: {
type: String,
default: () => 'foo'
}
},
methods: {
doSomethingWithBar () {
this.$emit('update:bar', 'bar')
}
},
template: '<button #click="doSomethingWithBar">{{ bar }}</button>'
})
example parent:
<child-component /> <!-- notice no :bar.sync -->
Example on codepen:
https://codepen.io/anon/pen/jXaGJg
My current solution is:
Vue.component('child-component', {
props: {
bar: {
type: String,
default: () => 'foo'
}
},
data () {
return {
innerBar: null
}
},
mounted () {
this.innerBar = this.bar
},
methods: {
doSomethingWithBar () {
this.innerBar = 'bar'
}
},
template: '<button #click="doSomethingWithBar">{{ bar }}</button>',
watch: {
bar () {
this.innerBar = this.bar
},
innerBar () {
if (this.innerBar !== this.bar) {
this.$emit('update:bar', this.innerBar)
}
}
}
})
But this requires a lot of unnecessary code and I am quite sure there is a better idea.
UPDATE: (Actual context)
I am designing an audio component that wraps controls and playing Audio.
Example for audio.loop (I would have to do something similar to currentTime, paused, volume, etc.):
export default {
props: {
loop: {
type: Boolean,
default: () => false
},
audio: {
required: true,
type: HTMLAudioElement
},
},
data () {
return {
innerLoop: null
}
},
methods: {
toggleLoop () {
if (this.innerLoop) {
this.innerLoop = false
} else {
this.innerLoop = true
}
}
},
watch: {
loop () {
this.innerLoop = this.loop
},
innerLoop () {
this.audio.loop = this.innerLoop
if (this.innerLoop !== this.loop) {
this.$emit('update:loop', this.innerLoop)
}
}
}
}
This works but is there a better way?

Vuefire how to setup db ref to dynamically change based on component props

I'm trying to setup dynamic binding of firebase node based on component data, like this
export default {
name: 'data',
props: {
api: {
type: String
},
section: {
type: String
}
},
firebase: {
apiData: {
source: (console.log('source', this.api), db.ref(this.api)),
asObject: true
}
},
updated: function() {
console.log('updated', this.api, this.section)
},
created: function() {
console.log('created', this.api, this.section)
}
}
My problem is, update event is fired, but apiData source update is not fired.
What is the correct way to do this with vuefire?
After some reading of vuefire docs, I came up with watch solution
data: function(){
return {
apiData: {}
}
},
created: function() {
this.$bindAsObject('apiData', db.ref(this.api))
},
watch: {
api: function() {
this.$bindAsObject('apiData', db.ref(this.api))
}
}