Is it possible to pass props as funcitions on VueJs?
<template>
<line-chart
class="card-content"
:chartData="lineData2('Temp')"
:options="options"
:width="800">
</line-chart>
</template>
The chartData prop can be used as a method? Is there any way to pass a method on a prop?
Cheers,
It depends on what you are trying to do. If you want to pass an actual function and not the result of a function, you can do:
<line-chart class="card-content" :chartData="() => lineData2('Temp')" :options="options" :width="800"></line-chart>
Which will pass the lineData2 function itself, however, it will still be executed in the parent scope and not in the component scope, so it won't have any access to the components this context.
Here's a JSFiddle: https://jsfiddle.net/rz8c1v4L/
If you just want to pass the result of the function then what you are doing is fine.
Yes you can. As long as your function returns a value. Everything should work.
Yes you can! You can achieve that by mentioning the type of your prop, as it is clearly written in Vue's documentation. For e.g.
Vue.component('example', {
props: {
propA: {
type: function
}
}
})
Also checkout this link
Related
I have a page with a component and the page needs to access a variable in that component. Would be nice if it were reactive. Then from the page I need to activate a function in the component. Would be nice if it could be done without a reactive variable. My question is 1: what's the best way to activate the function from the parent, for example when I click a button and 2: it seems very unintuitive and random to me that they aren't both possible in both directions? Anyone maybe know how Vue suggest you do it? This whole thing seems so complex relative to the relatively simple thing I'm trying to do.
I guess I try to use props? Or are refs a better option here?
So in general: you use refs, if you need the dom element, that's the whole purpose of refs. Since you don't mention that you n ed the dom element, you don't need to use that here.
There are 3 ways of communication: parent to child via props: https://vuejs.org/guide/components/props.html
child to parent via events
https://vuejs.org/guide/components/events.html
and anyone to anyone via event bus, which need an extra lib in vue3 and is out of scope for your question
https://v3-migration.vuejs.org/breaking-changes/events-api.html#event-bus
If you want to execute a function in the component whenever the value changes, you can put a watcher on the prop.
The other way around, from child to parent, you just create a listener to your emitted event and invoke a function of your choice. There are good examples in the docs in my opinion.
As per my understanding, You want to trigger the child component method from the Parent component without passing any prop as a input parameter and in same way you want to access child component data in the parent component without $emit. If Yes, You can simply achieve this using $refs.
You can attach the ref to the child component and then access it's variables and methods with the help of this $refs.
Live Demo (Just for a demo purpose I am using Vue 2, You can make the changes as per Vue 3) :
Vue.component('child', {
data: {
childVar: ''
},
methods: {
triggerEventInChildFromParent() {
console.log('Child Function triggered from Parent');
}
},
mounted() {
this.childVar = 'Child component variable'
}
});
var app = new Vue({
el: '#app',
methods: {
triggerEventInChild() {
this.$refs.child.triggerEventInChildFromParent()
}
},
mounted() {
console.log(this.$refs.child.childVar)
}
});
<script src="https://cdnjs.cloudflare.com/ajax/libs/vue/2.5.17/vue.js"></script>
<div id="app">
<button #click="triggerEventInChild">
Button in Parent
</button>
<child ref="child"></child>
</div>
I am trying to show a loading indicator which is located inside of a component that contains a slot element (lets call this the wrapper component). To do this, I have a function inside the wrapper that sets the state of the indicator based on an input boolean (setSpinnerVisible()). Now, I would like to execute this function from the component that uses this wrapper. To do this, in the parent component I use the v-slot property to get a reference to the function. I would like to be able to call this function inside the mounted() function, or from a function within methods.
However, I am not able to figure out how to do this. The only way I can think of is by passing this v-slot value into a function that is executed on an event like a button press, which works, but I also want to be able to call this method from a function that is not executed by an action in the layout (e.g. in the mounted() function).
This is (a part of) my wrapper component (the function that toggles the spinner is left out for brevity):
<template>
<slot v-bind:setSpinnerVisible="setSpinnerVisible"></slot>
...
<div class="spinner" v-show="spinnerVisible"></div>
</template>
This is (a part of) the component that uses the wrapper:
<Wrapper v-slot="{ setSpinnerVisible }">
...
</Wrapper>
I would like to be able to use the value of setSpinnerVisible inside the mounted function in one way or another, something like this fictional piece of code:
<script>
export default {
mounted() {
this.setSpinnerVisible(true)
}
}
</script>
I am using Vue 2.6.11
There are several approaches you could take.
For example, you could access the parent instance and call the method you need:
this.$parent.setSpinnerVisible()
Alternatively, you could create a gateway component that uses the Wrapper, gets setSpinnerVisible and passes it as a prop to the component that needs it.
You can use dependency injection. Described here: https://v2.vuejs.org/v2/guide/components-edge-cases.html#Dependency-Injection
So, in Wrapper.vue
<template>
...
</template>
<script>
export default {
provide () {
return {
setSpinnerVisible: this.setSpinnerVisible
}
}
}
</script>
And in your child component:
<Wrapper>
...
</Wrapper>
<script>
export default {
inject: ['setSpinnerVisible'],
mounted() {
this.setSpinnerVisible(true)
}
}
</script>
The last one would be my recommended approach because it's much neater and is not anti-pattern.
I am using a v-for inside a template to show a list from a computed property. But even though it works when i refresh, i cannot see the listed items when i firstly get on the page. If i v-for my contacts, i cannot filter.
So my data and computed methods look like this:
export default {
data() {
return {
contacts: this.$store.getters.loadedContacts,
search: ""
};
},
computed: {
filterContacts(contacts) {
return this.contacts.filter(contact => {
return contact.name.toLowerCase().match(this.search.toLowerCase());
});
}
};
And i call it in my HTML like this (filterContacts):
<v-list two-line v-if="contacts">
<template v-for="(contact, index) in filterContacts">
<v-list-tile-content>
<v-list-tile-title>{{ contact.name }}</v-list-tile-title>
<v-list-tile-action-text>{{ contact.position }}</v-list-tile-action-text>
</v-list-tile-content>
</template>
</v-list>
So the actual question is this: Why do need to refresh my page to see the results from the for loop ?
If i don't call the filterContacs, i cannot use my filter.
Any suggestions how to solve both filtering and v-for loop?
Thanks and sorry if this is a novice one!
Any help is much appreciated
Data of the component is set upon creation. The getter in the store probably doesn't return any data yet.
You can safely replace this.contacts in your computed with this.$store.getters.loadedContacts.
Other thing you can choose for, perhaps more elegant, is to use vuex's mapGetter helper. It reactively maps a vuex getter to your component's computed property (read more here: https://vuex.vuejs.org/guide/getters.html#the-mapgetters-helper).
With mapGetters you would:
...mapGetters({
contacts: 'loadedContacts'
})
And then just remove contacts from your data declaration.
Thanks! I actually observed at what you said. Indeed by replacing this.contacts with this.$store.getters.loadedContacts did fixed my problem. I removed also "contacts" from data().
Thanks!
I'm trying to pass php/laravel data to my component from a custom global variable. I've seen examples of this going into the new Vue({}) area directly but I haven't seen any way to pass this by going into right into the component
<script>
var itemData = //json object
</script>
<custom-component item-data="ITEMDATAVAR"></custom-component>
I should specify that I do have item-data in my component props. The issue is that I'm not sure how to tell my component's html that I'm passing the value of the variable itemData and not the string "itemData"
I think you are referring to dynamic props
<custom-component v-bind:item-data="ITEMDATAVAR"></custom-component>
or use the shorthand syntax
<custom-component :item-data="ITEMDATAVAR"></custom-component>
You should add the item-data to the props array like this:
Vue.component('custom-component', {
props: ['item-data'],
...
}
You can research this Vue.js example
Create a variable
new Vue({
el: '#el',
data: yourJsonObject
})
In you component you have to write about props
Vue.component('custom-component', {
props: ['item-data']
...
}
Pass the data to the component the same way
<custom-component item-data="ITEMDATAVAR"></custom-component>
I have not tested how it will work, guided by the documentation.
Still a little bit young in VueJS but I'm loving every bit of it. But now, fixated somewhere.
I want to initialize some values in data() using values passed via props. This is so that I can be able to mutate them later on, since it is not recommended to mutate props inside a component. In fact the official docs recommend this property initialization using prop values as shown below:
{
props: ['initialCounter'],
data: function () {
return { counter: this.initialCounter }
}
I have something like the one below:
<template>
<div class="well">
<!-- Use Prop value directly on the template: works (but of no help in initializing data) -->
Department: {{department.name}}
<!-- Use prop value but gotten via computed property: Works inside the template but not in the initialization -->
Department: {{fetchDepartment.name}}
<!-- Use the array I initialized with the prop value: Does not work -->
Department: {{this_department.name}}
</div>
</template>
<script>
export default {
name: 'test',
props: ['department'],
data() {
return {
this_department: this.department
// below does not work either
//this_department: this.fetchDepartment
}
},
created() {
// shows empty array
console.log(this.department)
},
mounted() {
// shows empty array
console.log(this.department)
},
computed: {
fetchDepartment() {
return this.department
}
}
}
</script>
As seen in the commented sections above, the initialization is not successful. Neither does the value of this.department appear either from the created() or the mounted() hooks. And note, I can see it is defined using the Chrome Vue Devtools. So my question is, how exactly should I initialize data() attributes using props values, or which is the best way of going around this issue?
I know my answer comes in late but it helps me and hopefully someone else coming here. When props' data are async:
// in the parent component
<template>
<child :foo="bar" v-if="bar" />
</template>
That way, you render the component when props are already available making it safer to follow the guide's recommended ways to initialize data value with props as so:
props: ['initialCounter'],
data: function () {
return {
counter: this.initialCounter
}
}
Happy coding!
You CAN modify a prop. Use the '.sync' modifier. I use it frequently because it is convenient and intuitive. This requires emitting an event to update the value on the parent. I am not really sure the warning of how it results in maintenance issues.
Another method I use if I want to modify a value and not update the parent is using Lodash clone. For example (assuming its available on mounted)
mounted(){
this_department = _.clone(this.department)
}
If you consistently want to mutate the prop and have it change with the parent, then use a computed property. However, in most cases you will want to depend on the state of that data within the component and change it using other functions and thus a computed property will not be what you need.
A computed property is the simplest way to provide a mutable version of a prop, but you might not want to lose data when the prop is updated. You could use an explicit watch.
Watchers
While computed properties are more appropriate in most cases, there
are times when a custom watcher is necessary. That’s why Vue provides
a more generic way to react to data changes through the watch option.
This is most useful when you want to perform asynchronous or expensive
operations in response to changing data.
This is most useful when you want to perform asynchronous or expensive
operations in response to changing data.