Flag of Ukraine
SymfonyCasts stands united with the people of Ukraine

Symfony UX & Chart.js

Keep on Learning!

If you liked what you've learned so far, dive in!
Subscribe to get access to this tutorial plus
video, code and script downloads.

Start your All-Access Pass
Buy just this tutorial for $12.00

With a Subscription, click any sentence in the script to jump to that part of the video!

Login Subscribe

We now know Stimulus pretty well, which is really just a nice JavaScript library that has nothing to do with Symfony. So then... what exactly is Symfony UX?

To answer that, go to https://github.com/symfony/ux. At its most basic, Symfony UX is a growing list of pre-built Stimulus controllers that you can install to get free functionality. For example, one of them is a controller that integrates Chart.js: a completely independent, lovely JavaScript-powered chart library.

This is perfect... because our sales are really starting to take off. People love our junk, uh, minimalist products! So let's install and use this UX package to build a sales graph on an admin page. I've already created that page at "/admin"... but it's not very interesting yet... and none of these links go anywhere.

Installing symfony/ux-chartjs

Ok: let's check out the docs for Symfony UX chartjs. Scroll down... Whoa. Stimulus and Chart.js are both pure JavaScript libraries. So it's a little interesting that the first step is to install a PHP package. Why are we doing that? Let's find out! Copy the composer require line and head over to your terminal.

I committed all my changes before hitting record so I can easily see any changes that the Flex recipe for this package might make. Paste and go:

composer require symfony/ux-chartjs:1.2.0

While this loads, your Encore build may start failing: don't worry about that for now. When it finishes, run:

git status

Interesting! This modified composer.json and composer.lock, which is totally normal. And the PHP package we just installed is actually a Symfony bundle, so its Flex recipe auto-enabled that bundle in config/bundles.php and updated the symfony.lock file.

UX PHP Packages Come with a JavaScript Package

But here's where things get interesting, really interesting. The recipe also updated our package.json file as well as some other file called assets/controllers.json.

Let's see what changed in package.json:

git diff package.json

Woh! It added a new package! But instead of a version number on the right, it's pointing to a directory inside of vendor/. Let's go check out that path. It was vendor/symfony/ux-chartjs/ then Resources/assets. Cool! This directory is a JavaScript package! How can I tell? It has a package.json file like all JavaScript libraries and, in the src/ directory, a Stimulus controller!

Well, in reality, when we use this package, the compiled controller in the dist/ directory is what will truly be used... but reading the one in src/ is easier.

So: what does this mean for us? It means that each Symfony UX library - like ux-chartjs - is actually two things: a PHP bundle and a JavaScript package. There is also some magic related to how this controller is registered in our app... but we'll talk about that in a few minutes.

Anyways, we have a new Symfony bundle in our vendor/ directory and a new JavaScript package registered in package.json - let me open that - which points to a directory in that bundle.

yarn install --force to Put the Package in node_modules/

Ok, back to the docs! The next step is to run yarn install --force. Copy that.

Normally, if you add a package to package.json, you need to run yarn install to actually download that into the node_modules/ directory. And actually, that's exactly what just happened to us! The Flex recipe added a new package to our package.json file.

Move over to the terminal that's running Encore, hit Ctrl+C to quit, then paste this command:

yarn install --force

This command forces yarn to reinstall our dependencies. The important part is that it copies the directory from the bundle into node_modules/ so that it looks and acts like any normal package.

Let's go find that: let me close a couple of things, then open node_modules/, and @symfony/. Cool! We of course have a webpack-encore/ directory but we also have a package called ux-chartjs.

Let's go re-build our assets:

yarn watch

Using the new Stimulus Controller

Ok: so how do we use the new Stimulus controller that lives in the package?

To answer that... let's keep following the docs! Scroll down. To build the JavaScript-powered chart, we're... woh! We're going to write PHP code!

Copy the top half of this code then head over and open up our admin controller, which is src/Controller/AdminController.php. Paste that code on top. And... let's see, we also need this ChartBuilderInterface argument. Add ChartBuilderInterface $chartBuilder. And... we need a use statement for this Chart class. I'll delete the "t", re-type, and hit tab to get it on top.

... lines 1 - 6
use Symfony\UX\Chartjs\Builder\ChartBuilderInterface;
use Symfony\UX\Chartjs\Model\Chart;
... line 9
class AdminController extends AbstractController
{
... lines 12 - 14
public function dashboard(ChartBuilderInterface $chartBuilder)
{
$chart = $chartBuilder->createChart(Chart::TYPE_LINE);
$chart->setData([
'labels' => ['January', 'February', 'March', 'April', 'May', 'June', 'July'],
'datasets' => [
[
'label' => 'Sales!',
'backgroundColor' => 'rgb(255, 99, 132)',
'borderColor' => 'rgb(255, 99, 132)',
'data' => [522, 1500, 2250, 2197, 2345, 3122, 3099],
],
],
]);
... lines 29 - 32
}
}

But wait: where did these classes come from? Remember: we did just install a new bundle... and bundles give us new classes and services. Autowiring ChartBuilderInterface will give us a new service that's really good at building chart data in PHP. Pass the $chart variable into the template: chart set to $chart.

... lines 1 - 14
public function dashboard(ChartBuilderInterface $chartBuilder)
{
... lines 17 - 29
return $this->render('admin/dashboard.html.twig', [
'chart' => $chart
]);
}
... lines 34 - 35

Okay. How do we render the chart? Go back to the docs and scroll down one more time. Ah ha! The bundle also gave us a new Twig helper. Copy that and go find the template for this page: templates/admin/dashboard.html.twig.

Then... all the way at the bottom, paste.

... lines 1 - 2
{% block body %}
<div class="container-fluid">
<div class="row">
... lines 6 - 101
<div class="col-10 mt-4">
<h1>Admin Dashboard</h1>
{{ render_chart(chart) }}
</div>
</div>
</div>
{% endblock %}

This uses the new function render_chart() from the bundle to render our chart variable.

I... guess we're done? Head back to our site and refresh the admin page. Whoa! We are done! We have a JavaScript-powered graph! That's extra amazing since all we did was composer require a PHP package, run yarn install, then write some PHP code!

That is the power of Symfony UX.

But... how exactly does this all work and connect together? What does render_chart() actually do? How is that Stimulus controller from the bundle being used? When will I find my car keys?

Let's answer... most of these questions, next.

Leave a comment!

17
Login or Register to join the conversation
Richard-L Avatar
Richard-L Avatar Richard-L | posted 8 months ago | edited

Nube Question:
Symfony 6
Charts working
_onConnect(event) works
event.detail.chart.options.onClick = (mouseEvent) => {} works when you click the chart area

How do I listen to an input tag in the twig and update the chart when the value changes?

Reply

Hey Richard!

Nah, it's a pretty reasonable questions ;).

First, nice job setting up the JavaScript to hook into the chart!

How do I listen to an input tag in the twig and update the chart when the value changes?

Here is what I would do:

A) Add a stimulus_action() to the input element - make it call, for example, some updateChart() method on your controller.

B) Inside of _onConnect(event) (for reference for others, you correctly got that from the documentation - https://symfony.com/bundles/ux-chartjs/current/index.html#extend-the-default-behavior - set the Chart object on a property on your Stimulus controller:

_onConnect(event) {
    // set the Chart object on a property so you can use it later
    this.chart = event.detail.chart;
}

C) Finally, inside of the updateChart() method, you can use the this.chart object and any other info you need to update the chart:

updateChart(event) {
    const input = event.target;
    const inputValue = input.value;

    // to update the chart, follow the chart.js docs
    // e.g. https://www.chartjs.org/docs/latest/developers/updates.html
    this.chart.data.datasets...
}

I'm assuming that you want to update the Chart object in JavaScript by hand. Another thing you could do is make an Ajax call to some Symfony controller that returns a new, fully-rendered Chart, which you could then put onto the page to render a brand new chart.

Cheers!

Reply

Hi,

Despite installing version 1.2.0 I can't get rid of this error:
<br />"./node_modules/@symfony/ux-chartjs/dist/controller.js" contains a reference to the file "stimulus".<br />This file can not be found, please check it for typos or update it if the file got moved.<br />

It is obvious that it originates on this line var _stimulus = require("stimulus"); from the dist version or import { Controller } from 'stimulus'; from the src one.

Maybe I need to updated to @hotwired/stimulus but no sure how to get it rebuild

<b>Edit</b>
Changed dist version to var _stimulus = require("@hotwired/stimulus"); and the error is gone... too hacky for my taste

Reply

Hey danresmejia!

Hmm, well that's no fun! So, if you're using Version 3 of Stimulus (the one where the package name is "@hotwired/stimulus" and not "stimulus"), then you need version 2.0 (or greater) of symfony/ux-chartjs. Really, the only difference between the 1.x and 2.x of the UX packages is that 2.x starts importing @hotwired/stimulus (instead of stimulus).

Hope that clarifies!

Cheers!

Reply
Kirill Avatar

If you have a problem with "has unmet peer dependency" or undefined package stimulus, it's because you are using stimulus v3 but by installing "composer require symfony/ux-chartjs:1.2.0" you get bundle with package reference to 'stimulus' (v2) inside vendors

So you need to install "symfony/ux-chartjs" v2+, and before it you must update symfony/flex package (composer update symfony/flex) otherwise composer will throw an error

Reply

Hey @Hainovsky,

Thanks for sharing detailed explanation. BTW exact this installation string is mentioned in course code and also there is video note ;)

Cheers!

Reply
Emus Avatar

Hi,
Does symfony ux Chartsjs work in easyadmin3 dashboard?

Reply

Hey Emilio,

Sure, it should work! With EasyAdminBundle v3 you can add Webpack Encore entries, that's exactly what you need instead of static addJsFile() method calls. You just need to import the ChartJS code in the Webpack Encore entry and write the implementation of it.

Cheers!

Reply
Emus Avatar

Sorry, I was referring to symfony / ux-chartjs. Can it be integrated into the EasyAdmin 3v dashboard?

Reply

Yes, i was integrate it yesterday

1) need rewrite layout.html.twig
1.1) create folder templates/bundles/Easyadmin/
1.2) create in this folder layout.html.twig
1.3) copy intire code from vendor/...../views/layout.html.twig yo your 1.2)
1.4) add stymulus to css and to js like a encore_entry_link_tags('app')
1.5) yarn watch
1.6) create own controller in admin/Dashboard with php code from symfony/ux and render 1.7
1.7) add your page with chart to template like in body {{ render_chart(chart) }}
1.8) enjoy your work

I do not know if it is allowed by symfonycasts rules, but i can create tutorial and make repository and put here link.

RYAN should allow me to do it.

1 Reply
Emus Avatar

Thanks,
What I did was add a new JS (called dashboard.js inside import './bootstrap';) in webpack.config.js and then in DashboardController.php (EasyAdmin) add the assets with -> addWebpackEncoreEntry ('dashboard'). [in configureAssets() method]
It worked!.
Not override easyadmin's layout.html, but I tried that method and it worked too.

Reply
Dmitry-K Avatar
Dmitry-K Avatar Dmitry-K | Emus | posted 1 year ago | edited

Thanks! Also worked for me!

1) I've created <b>dashboard.js</b> in <b>/assets/scripts/</b> with content:
import '../bootstrap';

Used ".." cause of my folder structure.

2) Injected <b>dashboard.js</b> into <b>webpack.config.js</b> file:
.addEntry('dashboard', './assets/scripts/dashboard.js')

3) Overrided <b>configureAssets</b> method in DashboardController class:


public function configureAssets(): Assets {
        return parent::configureAssets()->addWebpackEncoreEntry('dashboard');
}
1 Reply

Hey Dmitriy,

Thank you for sharing your solution and confirming it works for you too!

Cheers!

Reply

Hey Emilio,

Great! I'm happy it worked for you. Thanks for sharing your solution with others!

Cheers!

Reply

How to create transparent background on chart Chart::TYPE_LINE? Removed this backgroundColor, nothing happens, light grey background exist....

Reply

Solved - 'backgroundColor' => 'rgba(255, 255, 255, 0)', Last parameter is transparency. Thanks to all

Reply

Hey Maxim,

You're right, good catch! I'm glad you were able to solve this by yourself

Cheers!

Reply
Cat in space

"Houston: no signs of life"
Start the conversation!

This tutorial works perfectly with Stimulus 3!

What PHP libraries does this tutorial use?

// composer.json
{
    "require": {
        "php": ">=8.1",
        "ext-ctype": "*",
        "ext-iconv": "*",
        "composer/package-versions-deprecated": "1.11.99.1", // 1.11.99.1
        "doctrine/annotations": "^1.0", // 1.11.1
        "doctrine/doctrine-bundle": "^2.2", // 2.2.3
        "doctrine/doctrine-migrations-bundle": "^3.0", // 3.0.2
        "doctrine/orm": "^2.8", // 2.8.1
        "phpdocumentor/reflection-docblock": "^5.2", // 5.2.2
        "sensio/framework-extra-bundle": "^5.6", // v5.6.1
        "symfony/asset": "5.2.*", // v5.2.3
        "symfony/console": "5.2.*", // v5.2.3
        "symfony/dotenv": "5.2.*", // v5.2.3
        "symfony/flex": "^1.3.1", // v1.18.5
        "symfony/form": "5.2.*", // v5.2.3
        "symfony/framework-bundle": "5.2.*", // v5.2.3
        "symfony/property-access": "5.2.*", // v5.2.3
        "symfony/property-info": "5.2.*", // v5.2.3
        "symfony/proxy-manager-bridge": "5.2.*", // v5.2.3
        "symfony/security-bundle": "5.2.*", // v5.2.3
        "symfony/serializer": "5.2.*", // v5.2.3
        "symfony/twig-bundle": "5.2.*", // v5.2.3
        "symfony/ux-chartjs": "^1.1", // v1.2.0
        "symfony/validator": "5.2.*", // v5.2.3
        "symfony/webpack-encore-bundle": "^1.9", // v1.11.1
        "symfony/yaml": "5.2.*", // v5.2.3
        "twig/extra-bundle": "^2.12|^3.0", // v3.2.1
        "twig/intl-extra": "^3.2", // v3.2.1
        "twig/twig": "^2.12|^3.0" // v3.2.1
    },
    "require-dev": {
        "doctrine/doctrine-fixtures-bundle": "^3.4", // 3.4.0
        "symfony/debug-bundle": "^5.2", // v5.2.3
        "symfony/maker-bundle": "^1.27", // v1.30.0
        "symfony/monolog-bundle": "^3.0", // v3.6.0
        "symfony/stopwatch": "^5.2", // v5.2.3
        "symfony/var-dumper": "^5.2", // v5.2.3
        "symfony/web-profiler-bundle": "^5.2" // v5.2.3
    }
}

What JavaScript libraries does this tutorial use?

// package.json
{
    "devDependencies": {
        "@babel/preset-react": "^7.0.0", // 7.12.13
        "@popperjs/core": "^2.9.1", // 2.9.1
        "@symfony/stimulus-bridge": "^2.0.0", // 2.1.0
        "@symfony/ux-chartjs": "file:vendor/symfony/ux-chartjs/Resources/assets", // 1.1.0
        "@symfony/webpack-encore": "^1.0.0", // 1.0.4
        "bootstrap": "^5.0.0-beta2", // 5.0.0-beta2
        "core-js": "^3.0.0", // 3.8.3
        "jquery": "^3.6.0", // 3.6.0
        "react": "^17.0.1", // 17.0.1
        "react-dom": "^17.0.1", // 17.0.1
        "regenerator-runtime": "^0.13.2", // 0.13.7
        "stimulus": "^2.0.0", // 2.0.0
        "stimulus-autocomplete": "^2.0.1-phylor-6095f2a9", // 2.0.1-phylor-6095f2a9
        "stimulus-use": "^0.24.0-1", // 0.24.0-1
        "sweetalert2": "^10.13.0", // 10.14.0
        "webpack-bundle-analyzer": "^4.4.0", // 4.4.0
        "webpack-notifier": "^1.6.0" // 1.13.0
    }
}
userVoice