Integrating FOSJsRoutingBundle
Open Components/RepLogApp.js
and search for Routing
:
// ... lines 1 - 8 | |
class RepLogApp { | |
// ... lines 10 - 43 | |
loadRepLogs() { | |
$.ajax({ | |
url: Routing.generate('rep_log_list'), | |
// ... lines 47 - 50 | |
}) | |
} | |
// ... lines 53 - 194 | |
} | |
// ... lines 196 - 214 |
Guess what? This Routing
variable is a global variable. Boo! It's our last one. In templates/
, open the base layout:
// ... lines 1 - 96 | |
{% block javascripts %} | |
<script src="{{ asset('bundles/fosjsrouting/js/router.js') }}"></script> | |
<script src="{{ path('fos_js_routing_js', { callback: 'fos.Router.setData' }) }}"></script> | |
// ... lines 100 - 101 | |
{% endblock %} | |
// ... lines 103 - 106 |
Other than a polyfill - which we won't talk about - there are only two script tags left. These give us the Router
variable and they come from FOSJsRoutingBundle: a really cool bundle that allows you to generate URLs from Symfony routes in JavaScript.
Our goal is clear: refactor our code so that we can require the Router instead of relying on the global variable.
Requiring the router.js File
The first interesting thing is that this is not a Node package. Nope, it's a normal PHP package that happens to have a JavaScript file inside. But, that doesn't really make any difference... except that the path for it is ugly: it lives in vendor/friendsofsymfony/jsrouting-bundle/Resources/public/js/router.js
. Wow! Ok then: const Routing = require()
, then go up a few directories and follow the path: vendor/friendsofsymfony/jsrouting-bundle/Resources/public/js/router.js
:
// ... lines 1 - 5 | |
const Routing = require('../../../vendor/friendsofsymfony/jsrouting-bundle/Resources/public/js/router.min.js'); | |
// ... lines 7 - 215 |
Simple enough! Let's try it! In your browser, refresh! Bah! Error!
The route
rep_log_list
does not exist
Booo! This error comes from inside the Router. Here's what's going on: this JavaScript library is more complex than most. The first script tag gives us the Router variable. But the second executes a dynamic endpoint that fetches a JSON list of the route information and then sets that on the router.
When we simply require the router... we do get the Router object... but it has no routes! So the question is: how can we get the dynamic route info so that it can be set into the router?
Actually, this is possible! If you look at the Usage section of the bundle's docs, it talks about how to integrate with Webpack Encore. Basically, by running a bin/console
command, you can dump your route information to a static JSON file. Then, you can require that JSON from Webpack and set it on the Router. Oh, and don't worry about this import
syntax - it's basically the same as require()
, and we'll talk about it next.
So this is really cool! It shows how you can even require JSON files from JavaScript! But... it has a downside: each time you add a new route, you need to re-run the command. That can be a pain during development. It's still a great option - and is a bit faster on production - but it does have that weakness.
Creating the Fake Router Module
And there is another option. It's not quite as fancy or awesome... but it's easier. Inside assets/js/Components
, create a new file called Routing.js
. Inside, um, just say, module.exports = window.Routing
:
/** | |
* For now, we rely on the router.js script tag to be included | |
* in the layout. This is just a helper module to get that object. | |
*/ | |
module.exports = window.Routing; |
Yep! We are going to continue using the global variable. But now, we can at least require this file from everywhere else so that our code looks more responsible: const Routing = require('./Routing')
:
// ... lines 1 - 5 | |
const Routing = require('./Routing'); | |
// ... lines 7 - 215 |
And now, when we refresh, it works. The cool thing about this hacky solution is that if you want to change to the better solution later, it's easy! Just put the correct code in Router.js
, and everything will already be using it. Nice!
Hello, there is something I don't understand with FosJsRouting ...
I installed it, and I configured it like this:
<b>Routing.js</b>
<b>app.js</b>
And in my <b>base.html.twig</b>, before all my others javascript files :
If I launch the web page, I've :
<b>Uncaught Error: The route "validation_index" does not exist.
</b>
But if I do the same thing in a <b>twig template</b> in the <b>javascript block</b> :
it works...
So how can I make this work from my <b>app.js</b>?
Knowing that when I debug to see the list of available routes, I have the desired route