Passing data from Craft CMS to a Vue component

Written By Steven Grant
Posted on

At the tail end of 2018, I'd been hooking up Craft CMS to some sweet interactive charts for a client's long-form content Matrix field.

Your chart library options

There are a plethora of JavaScript charting libraries out there in the JavaScript ecosystem like Highcharts, Chart.js, amCharts, canvasJS, Taucharts to name but a few. I've use both Highcharts and Chart.js on projects in the past.

The majority of these libraries have a chart for pretty much any scenario you're likely to come across in a project. I'd say the most important consideration in choosing a charting library is its documentation. Unless their docs provide clear detail on how to use their API, then I'd avoid.

Given I'd used Highcharts and Chart.js before (both with Vue) I wanted to try something different. I'd seen someone on Twitter mention Apexcharts a while back and they have a nice Vue integration as well so I'll be using this library as the basis for the post.

Setting up Craft for success

Here's the chart that I want to display on the front end - otherwise known as a Donut chart.

Screen Shot On 2018 12 20 At 11 03 14

I need a way to pass the label, percentage and colour from Craft to the chart. As I mentioned before, I'm working in the context of a Matrix field but the principles should be applicable to a regular field too.

I started by adding simpleDonut as a Matrix block and giving my block a heading field set as plain text and then a Craft table field of donutValues to store our data. That field contained columns of label (plain text), percentage (number) and colour (plain text).

Unfortunately, this didn't work for me and I'll come back to why later and why my new approach is more flexible. After making my change, here's what I ended up with from the client's AX.

Getting your Craft data

The first thing I want to do is grab all of my row data as a new donutValues variable as I'll reference that several times.

{# group all of the donut value data #}
{% set donutValues = block.donutValues.orderBy('percentage desc').all() %}

The most important thing to my chart (and the purpose of this post) is exposing the Craft data to a Vue component. Looking at the API for my Apexcharts, their Vue component expects a Vue prop of :series that expects an array of numbers. Here's the Twig to do that. It creates an empty array, loops over the values in my table and then merges my array with the result.

{# get the percentage values into an array of numbers for Vue #}
{% set donutPercentages = [] %}
{% for p in donutValues %}
    {% set donutPercentages = donutPercentages|merge([
        p.percentage
    ]) %}
{% endfor %}

What didn't work

Unfortunately, this didn't work. Despite my percentage column being set as a number, Craft was always returning the number as a string. Meaning my code block returned an array of strings rather than an array of numbers.

My end solution

I had to go third-party for a solution to this in the shape of Super Table by Verbb. I'm always hesitant to use a third-party plugin, especially a free one but Verbb have a solid reputation so was a safe bet.

Super Table gives you much more flexibility in a table by giving you access to native Craft fields as column types. The added benefit in my case was that as well as being able to use Craft's number field for the percentage column, I could also change colour to a dropdown field and then have a pre-defined list of colour labels and hex codes (have you met a client who can hex?).

Changing the donutValues field to a Super Table meant that my Twig block gave me just what I need: an array of numbers [59,19,15] 👍🏼

Passing the data to Vue via a prop

As we're working with an array, if we were to try render our donutPercentages variable, we'd get

Screen Shot On 2018 12 20 At 11 52 41

So we use the json_encode Twig filter to help us.

<apexchart
    type="donut"
    :width="420"
    :height="420"
    :series="{{ donutPercentages|json_encode }}"></apexchart>

And that's how we pass the data from Craft into a Vue component.

We still have a little more work though to have a functional donut chart. Our chart needs to have some options passed as a prop as well. I still need the labels and the colours for each.

Using the same method as before, building an array from table rows (although this time, for labels and colours it's an array of strings I want) - I create new variables of donutLabels and donutColours and loop over the values.


{# get the label column values into an array of strings #}
    {% set donutLabels = [] %}
    {% for p in donutValues %}
        {% set donutLabels = donutLabels|merge([
            p.label
        ]) %}
    {% endfor %}

    {# get the colors for each label into an array of strings #}
    {% set donutColors = [] %}
    {% for p in donutValues %}
        {% set donutColors = donutColors|merge([
            p.color.value
        ]) %}
    {% endfor %}

We need to pass both of these as a single prop to the Vue component.

To do that, we set another Twig variable called donutChartOptions but this time we're setting an object.

{# set the Apex Chart options and pass in our colors and labels #}
    {% set donutChartOptions = {
        dataLabels: {
            enabled: false
        },
        tooltip: {
            enabled: true
        },
        colors: donutColors,
        labels: donutLabels,
        legend: {
            show: false
        },
        animations: {
            enabled: true
        }
    } %}

As you can see in the snippet the colors property has a value of donutColors and labels is set to the value of donutLabels.

The Vue component then becomes

<apexchart
    type="donut"
    :width="420"
    :height="420"
    :options="{{ donutChartOptions|json_encode }}"
    :series="{{ donutPercentages|json_encode }}"></apexchart>

tl;dr

Building your own arrays and objects with Twig, used in conjunction with the Twig filter json_encode is the secret sauce when it comes to passing data from Craft into Vue.

Are you a fan of Craft and Vue? Have you other ways of passing data between Craft and Vue? At me.

  1. Craft CMS
  2. Apexcharts
  3. Matrix field