Can props be accessed in beforecreated of vue? - vue.js

In the vue docs, the part of "beforeCreate", I read the following:
Called immediately when the instance is initialized, after props resolution, before processing other options such as data() or computed.
Does this means that I can get props in beforeCreate hooks? if so, how can I get it?
In my child component, I try like this to get the message passed by parent component, but failed.
export default {
name: 'Child',
props: ['message'],
beforeCreate() {
console.log(this.message)
}
}

Please check the following snippet, looks like your code is fine:
const app = Vue.createApp({
data() {
return {
msg: 'aaa',
};
},
})
app.component('Child', {
template: `<div>{{ message }}</div>`,
props: ['message'],
beforeCreate() {
console.log('before create: ', this.message)
}
})
app.mount('#demo')
<script src="https://unpkg.com/vue#3.2.29/dist/vue.global.prod.js"></script>
<div id="demo">
<child :message="msg"></child>
</div>

Related

Passing data from route to router-view body

I have a single page application with the structure below.
|- App.vue
|- + Views
| |- Page.vue
|- + Components
| |- Slider.vue
EDIT 1: Solution thanks to #gengar.value
I solved the issue by passing params from Page.vue with
methods: {
emitIndex: function (index) {
this.$router.push({
name: "visualization",
params: { imgCat: "visualization", imgIndex: index },
});
},
}
App.vue containing the router-view container that is routing the Page.vue
Slider.vue is a component of App.vue
I want to pass index of clicked image and whole images data from Page.vue to App.vue then to Slider.vue in order to achieve decoupling Slider from Page for reusability purposes.
How can I pass user selected index from Page.vue too App.vue
I have tried to use, params, props and emit but failed.
Sample Page.vue
<template>
<div v-for="(item, index) in 3" :key="index"></div>
</template>
<script>
export default ({
data() {
return {
urls: ['url1', 'url2', 'url3']
}
}
})
</script>
Thanks in advance
EDIT 1: Solution thanks to #gengar.value
Problem solved by pushing params to router via Page.vue and listening it from Slider.vue as follows:
Page.vue
methods: {
passIndex: function (index) {
this.$router.push({
name: "visualization",
params: { imgCat: "visualization", imgIndex: index },
});
},
}
Slider.vue
watch: {
"$route.params.imgCat": function (val) {
this.state = val;
},
"$route.params.imgIndex": function (newVal) {
if (newVal != -1) this.imgState = newVal;
this.$router.push({ params: { imgIndex: -1 } });
}
My solution is a little bit complicated, but quite native since I only used Props and Emit.
You want to pass value between brother components, so you could simply try below:
App.vue
<template>
<div>
<Page :data="data" #syncData="syncData" />
<Slider :data="data" />
</div>
<template>
<script>
import Page from './Views/Page.vue'
import Slider from './Components/Slider.vue'
export default ({
components: {
Page,
Silder
},
data() {
return {
data: [] // init data in the parent component
}
},
methods: {
syncData(updatedImages) {
this.data = updatedImages
}
}
})
</script>
Page.vue
<template>
<div></div>
<template>
<script>
export default ({
props: {
data: { type: Array, default: () => [] }
},
methods: {
onSelectImage(images) {
this.$emit('syncData', images) // update selected data to App.vue
}
}
})
</script>
Slider.vue
<template>
<div></div>
<template>
<script>
export default ({
props: {
data: { type: Array, default: () => [] }
},
watch: {
data: {
handler(val) {
// when Page.vue emits updated data to App.vue,
// App.vue will pass data to Slider.vue
// and you could receive the updated data 'val' here
},
deep: true
}
}
})
</script>
Update: Sorry I misunderstood before. If you are using vue-router components and assigned different paths (eg. '/page' and '/slider'), you can use
this.$router.push({ path: '/path', query: selectedImage })
in Page.vue and get url query in Slider.vue.
Alternative methods could be using Cookie.js or sessionStorage (not pretty tho). Also you could try Vuex if the specific condition suits you.

Passing data from a Child Component to the Parents Pop in VueJs

I have a button component which calls an API, and I want to push the returned response up to the parent, where it will become the 'translatedText' prop, however, I believe I'm using the $emit incorrectly, due to the error: `Uncaught (in promise) TypeError: Cannot read properties of undefined (reading '$emit'). How do I best capture the response data and pass it to my parent prop, and is using $emit the best use in this instance?
TranslationButton.vue
<template>
<b-button type="is-primary" #click="loadTranslations()">Übersetzen</b-button>
</template>
<script>
export default {
name: "TranslationButton",
props: {
translatedText: ''
},
methods: {
loadTranslations() {
fetch('http://localhost:3000/ccenter/cc_apis')
.then(function(response) {
return response.text();
})
.then(function(data) {
console.log(data);
this.$emit('translatedText', this.data);
console.log(data)
})
},
},
};
</script>
Parent Component Props:
props: {
data: Array,
translatedText: '',
showAttachments: {
type: Boolean,
default: false,
}
},
How Child Component is called in Parent Component:
<translation-button #translatedText="loadTranslations()" />
Best practise when passing data from child to parent is emitting events.
this.$root.$emit('translatedText', this.data);
than
this.$root.$on('translatedText', () => { // do stuff })
by emits you pass value to parent component,
#translatedText="loadTranslations()" - its event listner, fireing on your child comp emit
do #translatedText="loadTranslations" instead of #translatedText="loadTranslations()"
and add this loadTranslations as a method to parent comp
BTW
if you dont use arrow funcs, and you use this.data it's pointing to object passed to .then, it will be undefined i guess...
The problem is with the usage of this. It does no longer point to your component inside the promise then() method.
You should create a new variable and initialize it with the value of this and use that variable to emit the event.
E.g.
loadTranslations() {
const _this = this;
fetch().then(response => _this.$emit(response));
}
if you want to pass data from child to parent, you need to use $emit like the below code
child:
<template>
<b-button type="is-primary" #click="loadTranslations">Übersetzen</b-button>
</template>
<script>
export default {
name: "TranslationButton",
props: {
TranslatedText: ''
},
methods: {
loadTranslations() {
const self= this; // change added
fetch('http://localhost:3000/ccenter/cc_apis')
.then(function(response) {
return response.text();
})
.then(function(data) {
console.log(data);
self.$emit('changeTitle', data) // change added
})
}
}
</script>
parent:
<template>
<translation-button #changeTitle="ChangeT" />
</template>
......
methods:{
ChangeT(title)
{
console.log(title)
},
}

How to set and pass a JSON prop through routes

In vue.js
route.js
[{path: "/path", name: "acomp_name", component: PathComp, props: { abc: {} }}]
comp.vue
<script>
...omitted_for_brevity,
methods: {
changeRoute(json_sample){
this.$router.push({name: "acomp_name", params: { abc: json_sample })
}
}
</script>
Is there a way I can set the props which is an object to return json sample which is another object, like this
that is can I set the value of props of the router in a push
if indeed it is not supported in vue-router4 . what approach has been used or is being used to do this?
I am grateful to God Almighty for helping me to create an intuitive and reliable answer,
N<>B solution works with vue3 and vue-router4x
in the comp.vue
somewhere inside the template I have a nested or child component
so
<template>
<p>...</p>
...omitted_for_brevity
<router-view :prop_from_router.js="this.state.a_key_I_want_to_use"/>
</template>
still in comp.vue
<script>
...omitted_for_brevity
setup(){
const s = reactive({})
return {s}
},
methods: {
changeRoute(t)
this.state.a_key_i_want_to_use = t
}
}
</script>

Properly alert prop value in parent component?

I am new to Vue and have been very confused on how to approach my design. I want my component FileCreator to take optionally take the prop fileId. If it's not given a new resource will be created in the backend and the fileId will be given back. So FileCreator acts as both an editor for a new file and a creator for a new file.
App.vue
<template>
<div id="app">
<FileCreator/>
</div>
</template>
<script>
import FileCreator from './components/FileCreator.vue'
export default {
name: 'app',
components: {
FileCreator
}
}
</script>
FileCreator.vue
<template>
<div>
<FileUploader :uploadUrl="uploadUrl"/>
</div>
</template>
<script>
import FileUploader from './FileUploader.vue'
export default {
name: 'FileCreator',
components: {
FileUploader
},
props: {
fileId: Number,
},
data() {
return {
uploadUrl: null
}
},
created(){
if (!this.fileId) {
this.fileId = 5 // GETTING WARNING HERE
}
this.uploadUrl = 'http://localhost:8080/files/' + this.fileId
}
}
</script>
FileUploader.vue
<template>
<div>
<p>URL: {{ uploadUrl }}</p>
</div>
</template>
<script>
export default {
name: 'FileUploader',
props: {
uploadUrl: {type: String, required: true}
},
mounted(){
alert('Upload URL: ' + this.uploadUrl)
}
}
</script>
All this works fine but I get the warning below
Avoid mutating a prop directly since the value will be overwritten
whenever the parent component re-renders. Instead, use a data or
computed property based on the prop's value. Prop being mutated:
"fileId"
What is the proper way to do this? I guess in my situation I want the prop to be given at initialization but later be changed if needed.
OK, so short answer is that the easiest is to have the prop and data name different and pass the prop to the data like below.
export default {
name: 'FileCreator',
components: {
FileUploader
},
props: {
fileId: Number,
},
data() {
return {
fileId_: this.fileId, // HERE WE COPY prop -> data
uploadUrl: null,
}
},
created(){
if (!this.fileId_){
this.fileId_ = 45
}
this.uploadUrl = 'http://localhost:8080/files/' + this.fileId_
}
}
Unfortunately we can't use underscore as prefix for a variable name so we use it as suffix.

VueJS Passing computed data as a prop returns undefined

I've tried and tried, but i can't figure it out the problem. From what I could read elsewhere, the variable passed to the child component gets sent as undefined before the data is available in the parent.
Please see here for reference:
the code in codesandbox
<template>
<div id="app">
<child :parentData="data.message"/>
</div>
</template>
<script>
import Child from "./components/Child";
export default {
name: "App",
components: {
Child
},
computed: {
quote() { return 'Better late than never' }
},
data() {
return {
data: { message: this.quote } ,
thisWorks: { message: "You can see this message if you replace what is passed to the child" }
};
}
};
</script>
Then in the child:
<template>
<div>
<h1>I am the Child Component</h1>
<h2> {{ parentData }}</h2>
</div>
</template>
<script>
export default {
name: "Child",
props: {
parentData: { type: String, default: "I don't have parent data" },
},
};
</script>
The answer is, you cannot access the value of this.quote because at the moment the data objectis creating, the computed object actually does not exist.
This is an alternative, we will use the created() lifecycle hook to update the value of data object:
created(){
this.data = {
message: this.quote
}
},
You don't need to change any things, just adding those line of codes is enough.
I've already tested those codes in your CodeSandbox project and it works like a charm.
Hopefully it helps!