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
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();
}
},
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)
},
....
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>
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?
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))
}
}