I'm using VueCharts which is a Google Charts plugin for vue.
I'm trying to give the newer Material Design looks to the charts. I've tried passing "google.charts.Bar" to chart-type prop and it did work. However, many of the options are ignored because, as stated in the Google Charts docs, the options object needs to be converted by using google.charts.Bar.convertOptions(options)
, something the plugin doesn't do.
Looking at the source, the plugin installs a 'vue-chart' component. This component uses ChartWrapper
to handle loading the chart libraries, like so:
methods: {
buildWrapper (chartType, dataTable, options, containerId) {
let wrapper = new google.visualization.ChartWrapper({
chartType: chartType,
dataTable: dataTable,
options: options,
containerId: containerId
})
return wrapper
},
So all I need is to override this method to convert the options before passing them to the ChartWrapper.
But how? I haven't found a way to simply override a component method in vue docs. I could create a new component and pass the converted options down, but I need access to the google object, which is only loaded internally by the plugin.
I have also read I could use mixins, but it's not clear how. This doesn't work:
Vue.component('MyCustomChart', {
mixins: ['vue-chart'],
methods: {
buildWrapper (chartType, dataTable, options, containerId) {
let wrapper = new google.visualization.ChartWrapper({
chartType: chartType,
dataTable: dataTable,
options: google.charts.Bar.convertOptions(options), // that's all I need
containerId: containerId
})
return wrapper
},
}
})
[Vue warn]: Failed to mount component: template or render function not defined. (found in MyCustomChart)
To override a style, you have two options. Either you can pass a style object, or you can pass a function that will obtain props regarding the current internal state of the component, thus enabling you to modify styles dynamically depending on the component state, such as isError or isSelected .
Overriding dependencies in Angular requires two key properties: provide — this points to the dependency that you wish to override. useClass — this points to the new dependency, which will override the existing dependency in the providers property.
Override props in codeYou reference the element you want to override by its name; so if you want to override an element, you must first name that element in Plasmic. // etc. A function that takes in the props and the component type that would be rendered, and returns a ReactNode .
Since Vue itself is a constructor, Vue. extend() is a class inheritance method. Its task is to create a sub-class of Vue and return the constructor. Vue. component() , on the other hand, is an asset registration method similar to Vue.
You can use Vue's extend method to customize plugin components.
In your case:
import VueCharts from 'vue-charts'
Vue.use(VueCharts);
const Base = Vue.options.components["vue-chart"];
const CustomChart = Base.extend({
methods: {
buildWrapper (chartType, dataTable, options, containerId) {
let wrapper = new google.visualization.ChartWrapper({
chartType: chartType,
dataTable: dataTable,
options: google.charts.Bar.coverOptions(options),
containerId: containerId
})
return wrapper
},
})
}
Vue.component('MyCustomChart', CustomChart);
(credit to Bert Evans for noting that you need to reference the base component from Vue.options.components
before extending to customize)
I played around with this a bit and I misled @thanksd above with my recommendation on what to extend. One way that works is this:
import VueChart from "vue-charts";
Vue.use(VueChart);
const BaseChart = Vue.options.components["vue-chart"];
const CustomChart = BaseChart.extend({
methods:{
buildWrapper (chartType, dataTable, options, containerId) {
let wrapper = new google.visualization.ChartWrapper({
chartType: chartType,
dataTable: dataTable,
options: google.charts.Bar.convertOptions(options),
containerId: containerId
})
return wrapper
}
}
});
Vue.component("custom-chart", CustomChart);
Further Explanation
As I thought, extending VueChart either through Vue's native extend, or through lodash
, will not achieve the expected results. The result of importing VueChart is a plugin definition. Both lodash
and Vue
will happily accept that as an object to extend, but neither will result in a Vue component. Trying to use the result of either will result in the error mentioned in the question, "template or render function not defined". That error is absolutely true; extending VueChart
extends an install function with a single method.
So how do you get the object to extend? vue-charts
doesn't expose it. The install just calls Vue.component('vue-chart', Chart)
.
Fortunately, Vue makes the globally installed components through Vue.options.components
. By extending Vue.options.components["vue-chart"]
we get a proper Vue component definition.
Finally, I was surprised google
was not available to @RegularEverydayNormalGuy. It has to be available; vue-chart
uses it. But he's right, it's not available immediately. vue-chart
loads the script asynchronously. Again, the plugin unfortunately doesn't make it available to you in any way, it just initializes itself after it's asynchronously loaded. There are ways to work around that, but at that point you should just probably submit a pull request.
options
is a property on vue-chart
. Why not just pass in the converted options?
new Vue({
data:{
convertedOptions: google.charts.Bar.convertOptions({<my options>})
}
})
And in the template
<vue-chart :options="convertedOptions"></vue-chart>
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With