5

I'm trying to create graphical components using Highcharts and Vue.js. I would like to pass the id attribute of the element to be used by Highcharts, but I can not get the attribute.

How can I set the id dynamically?

This is the HTML:

<objective-chart :element="'brick-chart'"></objective-chart>

And the javascript code:

<template>
    <div id="{{element}}"></div>
</template>

<script>
    import Highcharts from 'highcharts';
    export default{
        props: ['element'],
        ready(){
            $(function () {

                new Highcharts.Chart({
                    chart: {
                        renderTo: this.element,
                        type: 'bar',
                        height: 200,
                        margin: [0, 20, 0, 40]
                    },
                    title: {
                        text: null
                    },
                    xAxis: {

                        lineColor: null,
                        labels: {
                            rotation: -90
                        },
                        categories: [
                            'Brick'
                        ]
                    },
                    yAxis: [{

                        min: 0,
                        max:100,
                        endOnTick: true,
                        maxPadding: 0.02,
                        gridLineColor: null,

                        title: {
                            text: null
                        },
                        labels: {
                            y: -50
                        },


                    }],
                    legend: {
                        shadow: false,
                        verticalAlign: 'bottom'
                    },
                    tooltip: {
                        shared: true,
                        followPointer: true
                    },
                    plotOptions: {
                        column: {
                            grouping: true,
                            shadow: false,
                            borderWidth: 0
                        }
                    },
                    credits: {
                        enabled: false
                    },
                    series: [{
                        name: 'Objetivo',
                        color: 'rgba(224,224,224,1)',
                        data: [100],
                        pointPadding: 0.3,
                        pointPlacement: -0.2
                    }, {
                        name: 'Realizado',
                        color: 'rgba(106,166,46,.9)',
                        data: [76],
                        pointPadding: 0.4,
                        pointPlacement: 0.1
                    }, {
                        type:'spline',
                        name: 'Projeção',
                        color: 'rgba(106,166,46,.9)',
                        top: 10,
                        pointPlacement: -0.05,
                        data: [95],
                        marker: {
                            radius: 8,
                            lineColor: '#666666',
                            lineWidth: 1
                        }
                    }]
                });
            });
        }
    }
</script>

2
  • Instead of passing :element="'brick-chart'", could you please try to pass element="brick-chart", as you are trying to pass just a String? vuejs.org/guide/components.html#Literal-vs-Dynamic Commented Aug 5, 2016 at 3:01
  • @HectorLorenzo I tried this way but was having trouble finding the Highcharts the element ID. Anyway, no need now more pass an ID. Thank you for your help. Commented Aug 5, 2016 at 12:41

4 Answers 4

18

vue.js 2.0 example (Vue start to use virtual dom):
1) npm install highcharts
2) var Highcharts = require('highcharts');
3) Highcharts.chart(this.$el, {...}) in "mounted" method because this.$el isn't available before "mounted"
4) the Instance of highcharts should be destroyed in "beforeDestroy" method.

<template>
	<div><div>
</template>

<script>
var Highcharts = require('highcharts');
export default {
    name : "Chart",
    props : {
      series : {
        type: Array,
        required: true
      }
	},
  	data : function() {
      return {
        target: undefined
      }
    },
    mounted : function() {
      this.target = Highcharts.chart(this.$el, {
        title: {
          text: 'Monthly Average Temperature',
          x: -20 //center
        },
        subtitle: {
          text: 'Source: WorldClimate.com',
          x: -20
        },
        xAxis: {
          categories: ['Jan', 'Feb', 'Mar', 'Apr', 'May', 'Jun',
          'Jul', 'Aug', 'Sep', 'Oct', 'Nov', 'Dec']
        },
        yAxis: {
          title: {
          text: 'Temperature (°C)'
        },
        plotLines: [{
          value: 0,
          width: 1,
          color: '#808080'
        }]
      },
      tooltip: {
        valueSuffix: '°C'
      },
      legend: {
        layout: 'vertical',
        align: 'right',
        verticalAlign: 'middle',
  	        borderWidth: 0
      },
      series: this.series
    });
  },
  beforeDestroy: function() {
    this.target.destroy();
  },
}
</script>

And the parent component is:

<template>
  <div id="app">
    <h1>{{ msg }}</h1>
    <Chart :series = "initSeries"></Chart>
  </div>
</template>

<script>
import Chart from './Chart.vue';
export default {
  name: 'app',
  components : {Chart},
  data () {
    return {
      msg: 'Welcome to Your Vue.js App',
    }
  },
  computed : {
    initSeries : function() {
      return [{
              name: 'Tokyo',
              data: [7.0, 6.9, 9.5, 14.5, 18.2, 21.5, 25.2, 26.5, 23.3, 18.3, 13.9, 9.6]
          }, {
              name: 'New York',
              data: [-0.2, 0.8, 5.7, 11.3, 17.0, 22.0, 24.8, 24.1, 20.1, 14.1, 8.6, 2.5]
          }, {
              name: 'Berlin',
              data: [-0.9, 0.6, 3.5, 8.4, 13.5, 17.0, 18.6, 17.9, 14.3, 9.0, 3.9, 1.0]
          }, {
              name: 'London',
              data: [3.9, 4.2, 5.7, 8.5, 11.9, 15.2, 17.0, 16.6, 14.2, 10.3, 6.6, 4.8]
          }];
    }
  }
}
</script>

Sign up to request clarification or add additional context in comments.

1 Comment

The key is to wait for the mounted event (or onMounted event in the newer syntax) before calling Highcharts.chart. Thanks!
5

Edit: Check out the Vue 2 example from @Tody.Lu which is a great solution

You need to use renderTo: "#" + this.element to get a properly formatted ID selector.

I believe you can also use renderTo: this.$el without having an ID at all.

Edit: I checked my Highcharts component and this is how I have it:

$(this.$el).highcharts(data);

No need for an ID this way.

2 Comments

I don't think you need to, based on their provided documentation. renderTo automatically assumes that you are passing an id identifier. jsfiddle.net/wutkLwtt
Thanks for the help guys, the problem was solved with $(this.$el).highcharts(data); and now my component is reusable after a few more changes.
0

If you're using a central data store like Vuex, you can include chart increment property that stores the number of charts created, and increments when there is a new one.

Then you'd set the ID using a computed property:

computed: {
  id () {
    return 'highchart-' + idvar
  }
}

You could just as easily keep it in a global variable, but that's a bad idea.

Another option (one I've used in the past) is to create a random string in your component. I've used the UUID generator found at this answer.

if I use UUID function UUID.generate() to return a random string:

data () {
  return {
    uid: UUID.generate()
  } 
}

then use the generated uid property in a computed property:

computed: {
  id () {
    return 'chart-' + this.uid
  }
}

Then you'd use {{ id }} in your VM.

1 Comment

I'm using Vuex still due to low complexity of the project I'm working on. But I will test using a central data storage as you pointed me in another project that I will start. Thanks for your help.
-1

Take care, in your template you have:

<template>
    <div><div>
</template>

You need to have:

<template>
    <div></div>
</template>

Comments

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.