VueJS: How to access computed values in render function - vue.js

I currently have a component with this render function:
render(createElement, context) {
return createElement(
'div', {
'class': 'sliced'
},
[
createElement('div', {
'class' : 'sliced-inner',
'style' : context.style
}
)
]
)
},
and I've added functional: true. The "style" is a computed value, but it doesn't seem to get passed with the context object. Is there any way to access computed values in a Vue render function?

A functional component has no state, so a computed property is redundant. In the following example I'm creating a header component that toggles between foo and bar when clicked:
Vue.component('message', {
render (createElement) {
return createElement('h1', {
on: {
click: event => {
return this.foo = !this.foo
}
}
}, this.fooBar)
},
computed: {
fooBar() {
return (this.foo) ? 'foo' : 'bar'
}
},
data(){
return {
foo: true
}
}
});
As you can see the header value is based on a computed, and it works fine because it is not a functional component so can have state: https://jsfiddle.net/hwbbukvd/
If I make that a functional component by adding functional: true, then it does not work because it's display relies on the component having state: https://jsfiddle.net/cygjdjru/
See: https://v2.vuejs.org/v2/guide/render-function.html#Functional-Components
In your case, if you aren't looking for style to be reactive, then I'm guessing you just want to pass a prop
Vue.component('message', {
functional: true,
render(createElement, context) {
return createElement('h1', context.props.foo)
},
props: {
foo: {
required: true
}
}
});
See: https://jsfiddle.net/qhzh0a2c/

Related

VueX dispatch action doesnt work, no error displayed in console VueJs

I'm trying to use an action to call method with boolean value using the store
In the store app.js, i've defined :
export default {
namespaced: true,
state: () => {
return {
isScrollDisabled: true,
}
},
mutations: {
setScrollDisabled(state, value) {
state.isScrollDisabled = value
},
actions: {
setScrollDisabled(context, value) {
console.log('Action called in store')
context.commit('setScrollDisabled', value)
},
getters: {
getScrollDisabled: state => state.isScrollDisabled,
}
,
In the component, i dispatch the action like this :
this.$store.dispatch('app/setScrollDisabled', false) // with true or false
And in other component, i use the store getter to retrieve the value :
computed: {
isDisabled() {
return this.$store.getters.getScrollDisabled
},
I see nothing in the console and also in the VueJs Chrome extension, there are no event displayed
What i forgot here ?
More friendly and easy
computed: {
...mapGetters('app', [
'getScrollDisabled'
])
},
methods: {
...mapActions('app', [
'setScrollDisabled'
])
}

Return value from dataPointSelection event in Apexcharts

I have a question related to this question and this answer but they don't solve my question completely. I'm using vue and apexcharts and I would like to return a value or update a variable from an event. Is it possible to return something instead of printing it in the console?
Something like this:
events: {
dataPointSelection: function (event, chartContext, config) {
this.active = this.series[config.seriesIndex];
}
}
The problem that I face is that "this" makes reference to the overall vue component and therefore "series" and "active" cannot be found.
Here is the code that gives me"TypeError: this.series is undefined" when I click on a point data. The series data I get from the parent component and it looks like this:
[{"name":"S-1","data":[[2.65,100], [6.67,100]]}, {"name":"S-2","data":[[0,50],[2.65,50]]}]
<script>
import VueApexCharts from 'vue-apexcharts';
export default {
name: "myGraph",
components: {
apexchart: VueApexCharts,
},
props: {
series: {}
},
data: () => ({
active: undefined,
chartOptions: {
chart: {
width: '100%',
animations: {
enabled: false
},
events: {
dataPointSelection: function (event, chartContext, config) {
this.active = this.series[config.seriesIndex];
}
}
},
tooltip: {
intersect: true,
shared: false
},
markers: {size: 1},
}
}),
}
}
</script>
The idea is that on dataPointSelection, it should activate that serie in order to access later on other information that will be store in that object.
The easiest way is to bind the event directly in the component
<apexchart type="bar" #dataPointSelection="dataPointSelectionHandler"></apexchart>
methods: {
dataPointSelectionHandler(e, chartContext, config) {
console.log(chartContext, config)
}
}
Another way is to use ES6 arrow functions in your chart configuration
computed: {
chartOptions: function() {
return {
chart: {
events: {
dataPointSelection: (e, chart, opts) => {
// you can call Vue methods now as "this" will point to the Vue instance when you use ES6 arrow function
this.VueDemoMethod();
}
}
},
}
}
}
I think this is simply what you are looking for
chart: {
type: 'area',
events: {
dataPointSelection(event, chartContext, config) {
console.log(config.config.series[config.seriesIndex])
console.log(config.config.series[config.seriesIndex].name)
console.log(config.config.series[config.seriesIndex].data[config.dataPointIndex])
}
}
}
if you need by the click, this is better
chart: {
type: 'area',
events: {
click(event, chartContext, config) {
console.log(config.config.series[config.seriesIndex])
console.log(config.config.series[config.seriesIndex].name)
console.log(config.config.series[config.seriesIndex].data[config.dataPointIndex])
}
}
}
source How to access value on dataPointSelection function of Apexchart
documentation events https://apexcharts.com/docs/options/chart/events/

Change data between few router-view

I have two components, and can't pass data from one to another component
at first router-view have
data() {
return {
mode: true,
}
},
<input type="checkbox" class="switch-mode" v-model="mode" #change="$root.$emit('switch-mode', mode)">
and other is
data() {
return {
filter: {
mode: false,
order: 'DESC'
},
}
},
mounted() {
this.$root.$on('switch-mode', function (EventGrid) {
console.log('Grid mode is '+EventGrid); //this works it return true,false
this.filter.mode = EventGrid; // not working this.filter is undefined"
})
},
This happens because your function doesn't know what this is, you should explicitly tell it to use your component:
mounted() {
this.$root.$on(
'switch-mode',
(function (EventGrid) { ... }).bind(this)
)
}
Or, more effectively and modern, use an arrow function:
mounted() {
this.$root.$on('switch-mode', (EventGrid) => { ... })
}

VueJS how to filter a mapgetter array

I have the following mapgetter inside a component:
props: {
hideSidebarText: { type: Boolean, default: false }
},
computed: mapGetters({
menuItems: 'menuTypes',
}),
This computed property is used to create a list:
<div
class="sidebar"
v-for="item in menuItems"
:key="item.name"
>
The list has property hidden that i want to filter to show only the elements where hidden is false.
How can I extend the mapGetter inside computed section so I can do the filter in my component something like this:
computed: {
menuItems: function() {
return this.menuItems.filter(function(u) {
return u.hidden == false
})
}
I ended with the following solution, dont know if is the right way to do it but make sense to me:
computed: {
...mapGetters({
menuItems: 'menuTypes'
}),
filteredMenuItems: function() {
return this.menuItems.filter(function(i) {
return i.hidden == false;
});
}
},

`This` is undefined in vue.js watcher

I have component with watcher
props: {
propShow: { required: true, type: Boolean }
},
data() {
return {
show: this.propShow
}
},
watch: {
propShow: {
handler: (val, oldVal) => {
this.show = val;
}
}
}
Whenever parent component changes propShow this component must update it's show property. This component also modifies show property, that's why I need both: show and propShow, because Vue.js does not allow to change properties directly.
This line
this.show = val;
causes error
TypeError: Cannot set property 'show' of undefined
because this inside handler is undefined.
Why?
You will have to use function syntax here, as warned in the docs here:
Note that you should not use an arrow function to define a watcher (e.g. searchQuery: newValue => this.updateAutocomplete(newValue)). The reason is arrow functions bind the parent context, so this will not be the Vue instance as you expect and this.updateAutocomplete will be undefined.
So your code should be:
watch: {
propShow: {
handler: function(val, oldVal) {
this.show = val;
}
}
}
"function" is not es6 code, you should better write:
watch: {
propShow: {
handler(val, oldVal) {
this.show = val;
}
}
}