Routing and Data Access
=======================
We have already defined the basic routing structure. To define more routes, we simply extend the ``index.js`` file and add more components. We will start by building the list of modules. Create a new file ``src/js/routes/modules/index.jsx`` and add the following code:
.. code-block:: jsx
import m from "mithril";
import api from '../../api.js';
import Athena from "../../athena.jsx";
import AriaMenu from "../../components/aria-menu.jsx";
export default function ModulesIndex() {
return {
oninit: (vnode) => {
},
view: (vnode) => {
let modules = [];
if (vnode.state.modules) {
modules = vnode.state.modules.data.map((module) => {
let key = `module-${module.id}`;
return (
);
},
};
}
Here we see one of the main differences between React and Mithril. Because the routing is not defined within the JSX code, but externally, there is also no nesting of templates. Thus to use a application-level template that provides the generic structure, we invert the pattern and in the ``athena.jsx`` implemented the application-level template and then use that as a wrapping component for our new ``Index`` component.
Note, that there is a way to nest routes within the ``index.js``, that is not used in this tutorial, though. For further information consult the Mithril documentation.
With the component in place, we need to update the ``index.js`` to route to our new component:
.. code-block:: js
import m from "mithril";
import Athena from "./athena.jsx";
import ModulesIndex from "./routes/modules/index.jsx";
import '../styles/app.scss'
const root = document.getElementById("root");
m.route(root, "/", {
"/": Athena,
"/modules": ModulesIndex
});
Next update the ``athena.jsx`` to link the "My Modules" to our new route:
.. code-block:: jsx
...
...
As you can see, to link to another route, we provide the route path into the ``href`` attribute as part of a ``mithril.route.Link`` Element, that will create the prefix "/#!/". This needs to be included wherever we create a link to another route.
If you now try out the application, you will be able to navigate to the list of modules by clicking on the link. You will also see that the last part of the browser URL changes to "#!/modules". This is known as hash-bang (or just hash) routing. In this structure the main URL is the path to where the application is served from and the part after the hash (the so-called fragment) is used to implement the routing within the application. While full URL routing as in Ember or React looks a bit cleaner, functionally there is no difference between the two.
Loading Data
------------
At the moment our list of modules is empty, so we need to load some from the backend. To do this, we will add some code into the ``oninit`` function, which is automatically called when the component is initialised:
.. code-block:: js
oninit: (vnode) => {
m.request({
method: "GET",
url: `${api.base}/modules`,
}).then((data) => {
vnode.state.modules = data;
});
},
Unlike React, Mithril comes with data access included at a very basic level. Via ``mithril.request`` we can send arbitrary requests to the backend server. As you can see, the ``url`` is composed of the value ``api.base`` plus the specific path for all modules ``'/modules'``. For this to work, we need to import the ``api`` definition at the top of the ``index.jsx``:
.. code-block:: js
import api from '../../api.js';
Then we need to create ``src/js/api.js`` to define the basic backend API parameters:
.. code-block:: js
export default {
base: 'https://mht.uzi.uni-halle.de/client-seitige-web-anwendungen/api/example'
}
As in the past tutorials, you can replace the "example" part of the URL to get your own API instance. If you now look at the application, it should have loaded the data from the API.
In contrast to working with Ember and Redux, here you are working at a very low level, dealing directly with the JSONAPI response. You can see the effect of this if you look into the ``view`` method on the ``src/js/routes/modules/index.jsx``, where to access the list of modules, we use ``vnode.state.modules.data``. The first part ``vnode.state`` fetches the state and then in the code above we have assigned the list of modules to the ``modules`` key in the state. However, every JSONAPI response is an object with a single key ``data``, and only inside this key is the actual list of responses contained. As a result, when accessing the data, we have to navigate quite deep into the structure.
If, while developing, you are unsure about what the exact data structure is that the API returns, via the developer tools in the browser, you can always inspect the network traffic as well. If you select a request that goes to the backend API, then on the right you can see the actual JSON data that was returned in the response. The structure of the JSON data is then directly mirrored in what you get in the ``data`` parameter to the ``then`` callback function.