Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Overriding a component method

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)

like image 510
rzb Avatar asked Mar 30 '17 11:03

rzb


People also ask

How do you override component styles?

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 .

What is override in angular?

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.

How do you override props in react?

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 .

What is VUE extend?

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.


2 Answers

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)

like image 106
thanksd Avatar answered Nov 04 '22 11:11

thanksd


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.

Original Answer

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>
like image 29
Bert Avatar answered Nov 04 '22 10:11

Bert