How can I get the props values in Vue.js? - javascript

I'd like to get prop values in Vue.js, because i need to receive eid in my component to do verification, but i don't know how can i do this and if i do this.configs.eid is undefined. Another way is send data() value from my component A to component B.
I have this component and i need to get eid then insert in v-if
<section v-if="" >
<stream :configs="{eid : event.id}"></stream>
</section>
Another way is send this data() from component A to component B
data() {
return {
tipo: String,
link: String,
eid : 0
};
}
In component A my props is
props: {
configs: {
type: Object
}
},
I don't know how to get it, anybody knows? :/

Your question is not clear, there is no definition which component is A and which is B.
It seems that you may have mixed up parent & child, so I'll just try to show how to pass eid both ways.
If you want to pass eid from the child stream component to the parent for v-if check (which I think is the case), you need to use $emit, not prop:
Component A (Parent)
<section v-if="event.id == 0">
<stream #get-event-id="getEventId"></stream>
</section>
data() {
configs: {
event: {}
}
},
methods: {
getEventId(id) {
this.configs.event.id = id
}
}
Component B (Child)
data() {
event: {id: 0}
},
mounted(){
this.$emit('get-event-id', this.event.id)
},
That way if stream eid will be 0, like here, the component will not render.
However, if you would need to pass eid from parent component to stream component, it would look like this:
Component A (Parent)
<section v-if="">
<stream :configs="{eid : event.id}"></stream>
</section>
data() {
event: {id: 0}
}
Component B (Child)
props: ['configs'],
mounted(){
console.log(this.configs.eid)
},
This way you will get in console the parent's eid.

If you're trying to send the event.id to stream as property, then you can simply do it like this
<section v-if="" >
<stream :eventId="event.id"></stream>
</section>
Then from the Stream.vue component, you can receive the property like
export default {
name: "Stream",
props: ["eventId"]
}

Related

Vue Watcher not working on component created with Vue.extend

I have a Parent component with a select input which is bound through v-model to a variable in data.
Besides, I create child components dynamically using Vue.extend, which i pass the propsData which also includes the value of the select.
This components have a watcher for the prop that is related to the select input.
When i create the component it receives the props succesfully, The problem comes when I update the value of the select input that doesn't trigger the watcher on the child component.
I've been looking for similar situations but have not found something that helps me solve this problem, i don't know why it doesn't trigger the watcher on the child component when the select input changes.
Any help would be very preciated.
Here i create the component dynamically:
let PresupuestoFormularioVue = Vue.extend(PresupuestoFormulario)
let instance = new PresupuestoFormularioVue({
propsData: {
//The prop related to select input
seguro: this.seguro,
}
})
instance.$mount()
this.$refs.formularioContenedor.appendChild(instance.$el)
And this is the watcher in the component which isn't working:
watch:{
seguro:{
handler: function( newVal ){
console.log(newVal)
},
},
},
It's not the watch that doesn't work. It's the bindings. You're assigning the current value of this.seguro, not the reactive object itself. However, a new Vue() can add this binding for you.
As a sidenote, whether PresupuestoFormulario is a Vue.extend() doesn't matter. It can be any valid VueConstructor: a Vue.extend(), Vue.component() or a valid SFC (with name and template): export default {...}.
Here's how to do it:
methods: {
addPresupuestoFormulario() {
const div = document.createElement('div');
this.$el.appendChild(div);
new Vue({
components: { PresupuestoFormulario },
render: h => h("presupuesto-formulario", {
props: {
seguro: this.seguro
}
})
}).$mount(div)
}
}
The <div> initially appended to the parent will get replaced upon mounting with the actual template of PresupuestoFormulario and the bindings will be set, exactly as if you had <presupuesto-formulario :seguro="seguro" /> in the parent template from the start.
The really cool part about it is that the parent component doesn't need to have PresupuestoFormulario declared in its components.
Here's a working example:
const Test = Vue.component('test', {
template: `<div>message: {{message}}</div>`,
props: ['message'],
watch: {
message: console.log
}
})
new Vue({
el: '#app',
data: () => ({
msg: "¯\\_(ツ)_/¯"
}),
methods: {
addComponent() {
const div = document.createElement("div");
this.$el.appendChild(div);
new Vue({
components: {
Test
},
render: h => h("test", {
props: {
message: this.msg
}
})
}).$mount(div);
}
}
})
<script src="https://cdn.jsdelivr.net/npm/vue#2"></script>
<div id="app">
<input v-model="msg">
<button #click="addComponent">Add dynamic child</button>
</div>
A separate note, about using this.$el.appendChild(). While this works when you're using a root Vue instance (a so-called Vue app), it will likely fail when using a normal Vue component, as Vue2 components are limited to having only 1 root element.
It's probably a good idea to have an empty container (e.g: <div ref="container" />) in the parent, and use this.$refs.container.appendChild() instead.
All of props that you want check in watcher, should be a function. If you want read more about this go to vue document codegrepper.
watch: {
// whenever seguro changes, this function will run
seguro: function (newValue, oldValue) {
console.log(newValue,oldValue)
}
}

Relationship between props and data (vue)

In
https://codesandbox.io/s/v9pp6
the ChromePage component passes a prop to InventorySectionC:
<inventory-section-component :itemSectionProps="getItemSection">
</inventory-section-component>
InventorySectionC:
<template>
<div class="inventory-section-component">
<draggable v-model="itemSectionProps.itemSectionCategory">
<transition-group>
<div
v-for="category in itemSectionProps.itemSectionCategory"
:key="category.itemSectionCategoryId"
>
<!-- <p>{{ category.itemSectionCategoryName }}</p> -->
<inventory-section-group-component :itemSectionGroupData="category">
</inventory-section-group-component>
</div>
</transition-group>
</draggable>
</div>
</template>
<script>
import InventorySectionGroupComponent from "./InventorySectionGroupC";
import draggable from "vuedraggable";
export default {
name: "InventorySectionComponent",
components: {
InventorySectionGroupComponent,
draggable,
// GridLayout: VueGridLayout.GridLayout,
// GridItem: VueGridLayout.GridItem,
},
props: {
itemSectionProps: {
type: Object,
},
},
data() {
let itemSectionData = itemSectionProps;
return {
itemSectionData
};
},
};
</script>
<style scoped>
</style>
gives a warning at line:
<draggable v-model="itemSectionProps.itemSectionCategory">
:
Unexpected mutation of "itemSectionProps" prop. (vue/no-mutating-props)eslint
Why (how?) is itemSectionProps mutable?
Can a binding be created between props and data (all draggable samples use a data object:
https://sortablejs.github.io/Vue.Draggable/#/nested-example
https://github.com/SortableJS/Vue.Draggable/blob/master/example/components/nested-example.vue
)?
The idea is to have auto updating, nested, draggable components.
The code as is "works" but there are warnings/errs:
data() can't seem to see props:
And one more thing, which comes "first"? Data or props? can't seem to figure it out from the docs:
https://v2.vuejs.org/v2/guide/instance.html
Setting the props to a predefined value:
props: {
itemSectionProps: {
type: Object,
default: { itemSectionCategory: '' }
},
},
gives:
Type of the default value for 'itemSectionProps' prop must be a function. (vue/require-valid-default-prop).
I'm not sure why vue expects props to return a function.
After adding a default() onto props, props are empty when passed on to components:
https://codesandbox.io/s/sjm0x
(this grew too long for a comment, but probably already answers what you need)
itemSectionProps:
Your props are defined as:
props: {
itemSectionProps: {
type: Object,
},
},
You reference a prop of that object in your template
<draggable v-model="itemSectionProps.itemSectionCategory">
Vue cannot assume itemSectionProps.itemSectionCategory will exist in the future.
You should give it a default (see Vue docs) to create the expected values in that object.
props: {
itemSectionProps: {
type: Object,
default() {
return { itemSectionCategory: '' };
}
},
},
Do this for all the props you use on itemSectionProps.
data() can't seem to see props:
You can write this.itemSectionProps instead of only itemSectionProps.
But itemSectionProps is already defined in props. You can just remove itemSectionProps from data.
If you need to change that value, use a copy and promote changes with this.$emit.
You are probably calling the props without using this. on your data method.
You can as well define your variable itemSectionData as below:
data(){
return {
itemSectionData: Object.assign({}, this.itemSectionProps)
}
}
Object.assign()
The Object.assign() method copies all enumerable own properties from one or more source objects to a target object. It returns the target object. See more details here
Then use the newly defined variable itemSectionData within your component. Like:
<draggable v-model="itemSectionData.itemSectionCategory">
If you want to update the prop's values, simply emit an event from your child component and capture it on the parent as below:
methods:{
updatePropValues(){
this.$emit('updateProp', this.yourNewValues);
}
}
On the parent component handle the event as:
<inventory-section-component #updateProp="setNewValues" :itemSectionProps="getItemSection">
</inventory-section-component>
methods:{
setNewValues(newValues){
this.itemSections = newValues;
}
}
Check it out in action here

How to get the props value and use in lifehooks cycle of Vue JS

I'm searching a way to get the props value through some lifehooks like mounted or updated and trying to save the value with my v-model with some string. But I can't get it.
Though I tried :value on the input element with the props value and some string and I was able to get it, but it seems like I can't access it without v-model, as I researched v-model and :value can't be together.
The purpose is to get the value(with from props and some string) of a input tags.
Parent Component
<invite :user_token="user_token"/>
Child Component
export default {
props: ['user_token'],
data() {
return {
link: ''
}
},
mounted() {
console.log(this.user_token);
this.link = `"http://localhost/johndoe-vue/public/#/invite${this.user_token}"`;
},
updated() {
console.log(this.user_token);
this.link = `"http://localhost/johndoe-vue/public/#/invite${this.user_token}"`;
}
}
Welcome to SO Nigel!
Are you looking for something like this, perhaps?
ParentComponent.vue
<template>
<div id="wrapper">
<invite :userToken="userToken"></invite>
</div>
</div>
<script>
import Invite from "#/Invite.vue";
export default {
components: {
Invite
},
data() {
return {
userToken: "fooBar",
};
}
}
</script>
ChildComponent.vue
<template>
<div id="wrapper">
<p v-if="inviteLink != ''">{{ inviteLink }}</p>
</div>
</template>
export default {
props: {
userToken: {
type: String,
}
},
data() {
return {
inviteLink: ""
}
},
created() {
if(this.userToken != "") {
this.inviteLink == "/your-link-here/"+this.userToken;
}
}
}
Also, you should check out the Vue.js Style Guide. They've marked multi-word component names as essential. Your Invite component should be renamed to BaseInvite or something like that.
Have you tried to $emit this.link
Props is accessible through the $props property of your component. You would reference it like: this.$props.[property name]. $props is called an instance property; there are many of them and they are each accessible this way. See https://v2.vuejs.org/v2/api/#Instance-Properties
Keep in mind that the Vue life cycle methods are somewhat inconsistent. Which instance properties are accessible depends on the method (ie: you can't reference $el in created(...).
https://v2.vuejs.org/v2/guide/instance.html#Lifecycle-Diagram

Wrapping a JS library in a Vue Component

I need to know which is best practice for wrapping a JS DOM library in Vue. As an example I will use EditorJS.
<template>
<div :id="holder"></div>
</template>
import Editor from '#editorjs/editorjs'
export default {
name: "editorjs-wrapper",
props: {
holder: {
type: String,
default: () => {return "vue-editor-js"},
required: true
}
},
data(){
return {
editor: null
};
},
methods: {
init_editor(){
this.editor = new Editor({
holder: this.holder,
tools: {
}
});
}
},
mounted(){
this.init_editor();
},
//... Destroy on destroy
}
First:
Supose I have multiple instances of <editorjs-wrapper> in the same View without a :hook then all intances would have the same id.
<div id="app">
<editorjs-wrapper></editorjs-wrapper>
<editorjs-wrapper></editorjs-wrapper>
</div>
Things get little weird since they both try to process the DOM #vue-editor-js. Would it be better if the component generated a random id as default?
Second:
EditorJS provides a save() method for retrieving its content. Which is better for the parent to be able to call save() method from the EditorJS inside the child?
I have though of two ways:
$emit and watch (Events)
// Parent
<div id="#app">
<editorjs-wrapper #save="save_method" :save="save">
</div>
// Child
...
watch: {
save: {
immediate: true,
handler(new_val, old_val){
if(new_val) this.editor.save().then(save=>this.$emit('save', save)) // By the way I have not tested it it might be that `this` scope is incorrect...
}
}
}
...
That is, the parent triggers save in the child an thus the child emits the save event after calling the method from the EditorJS.
this.$refs.childREF
This way would introduce tight coupling between parent and child components.
Third:
If I want to update the content of the child as parent I don't know how to do it, in other projects I have tried without success with v-modal for two way binding:
export default{
name: example,
props:{
content: String
},
watch:{
content: {
handler(new_val, old_val){
this.update_content(new_val);
}
}
},
data(){
return {
some_js_framework: // Initialized at mount
}
},
methods: {
update_content: function(new_val){
this.some_js_framework.update(new_val)
},
update_parent: function(new_val){
this.$emit('input', this.some_js_framework.get_content());
}
},
mounted(){
this.some_js_framework = new Some_js_framework();
this.onchange(this.update_parent);
}
}
The problem is:
Child content updated
Child emit input event
Parent updates the two-way bidding of v-model
Since the parent updated the value the child watch updates and thus onchange handler is triggered an thus 1. again.

Setting props for components using v-for in Vue JS

I have a PhoneCard.vue component that I'm trying to pass props to.
<template>
<div class='phone-number-card'>
<div class='number-card-header'>
<h4 class="number-card-header-text">{{ cardData.phone_number }}</h4>
<span class="number-card-subheader">
{{ cardData.username }}
</span>
</div>
</div>
</template>
<script>
export default {
props: ['userData'],
components: {
},
data() {
return {
cardData: {}
}
},
methods: {
setCardData() {
this.cardData = this.userData;
console.log(this.cardData);
}
},
watch: {
userData() {
this.setCardData();
}
}
}
The component receives a property of userData, which is then being set to the cardData property of the component.
I have another Vue.js component that I'm using as a page. On this page I'm making an AJAX call to an api to get a list of numbers and users.
import PhoneCard from './../../global/PhoneCard.vue';
export default {
components: {
'phone-card': PhoneCard
},
data() {
return {
phoneNumbers: [],
}
},
methods: {
fetchActiveNumbers() {
console.log('fetch active num');
axios.get('/api').then(res => {
this.phoneNumbers = res.data;
}).catch(err => {
console.log(err.response.data);
})
}
},
mounted() {
this.fetchActiveNumbers();
}
}
Then once I've set the response data from the ajax call equal to the phoneNumbers property.
After this comes the issue, I try to iterate through each number in the phoneNumber array and bind the value for the current number being iterated through to the Card's component, like so:
<phone-card v-for="number in phoneNumbers" :user-data="number"></phone-card>
However this leads to errors in dev tools such as property username is undefined, error rendering component, cannot read property split of undefined.
I've tried other ways to do this but they all seem to cause the same error. any ideas on how to properly bind props of a component to the current iteration object of a vue-for loop?
Try
export default {
props: ['userData'],
data() {
return {
cardData: this.userData
}
}
}
Answered my own question, after some tinkering.
instead of calling a function to set the data in the watch function, all I had to do was this to get it working.
mounted() {
this.cardData = this.userData;
}
weird, I've used the watch method to listen for changes to the props of components before and it's worked flawlessly but I guess there's something different going on here. Any insight on what's different or why it works like this would be cool!

Categories

Resources