Routing Wednesday, May 29th, 2019
In JavaScript land you would use a third party routing library like react-router , vue-router or something similar (depending on the framework) to handle changes in the URL.
In Mint, routing is built into to language itself 🎉 so there is one less dependency to worry about.
Defining routes
You can use the
routes
block to define routes:
routes {
/path/to/match {
/* Do something here... */
}
/an/other/path/to/match {
/* Do something here... */
}
}
Basically you just define the path you want to match and in a block what should happen when that path is matched.
There two things to keep in mind:
- routes are matched from top to bottom
- only one route matches per navigation event
Matching parameters
You can use the standard colon parameters (
:param
) for path variables:
routes {
/posts/:id (id : String) {
/* Do something with the id here... */
}
/posts/:id/comments/:comment (id : String, comment : String) {
/* Do something with the id and comment here... */
}
}
The order of the variables does not matter but the names must match.
You can even match hash and query parameters:
routes {
/posts?page=:page (page : String) {
/* Do something with the page here... */
}
/#:hash (hash : String) {
/* Do something with the hash here... */
}
}
Matching all (not defined) paths
Using the
*
block matches all (non defined) paths:
routes {
* {
/* Matches anything. Useful for displaying a 404 page. */
}
}
It does not matter where this block is, it will always match last.
Navigating to a new URL
In Mint the language takes care of the navigation, all you have to do is
render normal anchor tags
<a href="/path/to/navigate"></a>
and the runtime will do the rest:
-
if the
href
attribute matches a route it will navigate to it and call the block without reloading the page, otherwise it will navigate to the URL normally -
browser specific behavior is kept:
- if the default behavior was prevented with preventDefault it does not navigate
-
ctrl
click opens the URL in a new tab (if applicable)
If you are interested in the actual implementation you can find it here .
Practical usage and example
In a real application what I usually do is to have an
enum
that represents all the pages that can occur like this:
enum Page {
NotFound
Register
Initial
Login
Home
}
I also have a store called
Application
with a state for the page:
store Application {
state page : Page = Page::Initial
fun setPage(page : Page) : Promise(Never, Void) {
next { page = page }
}
}
Then in the
Main
component I use that state to render the different pages:
component Main {
connect Application exposing { page }
fun render : Html {
<div>
<div>
<a href="/register">"Register"</a>
<a href="/login">"Login"</a>
<a href="/asdf">"404"</a>
<a href="/">"Home"</a>
</div>
<hr/>
case (page) {
Page::Register => <div>"Register"</div>
Page::NotFound => <div>"404"</div>
Page::Login => <div>"Login"</div>
Page::Home => <div>"Home"</div>
Page::Initial => <div></div>
}
</div>
}
}
And in the routes set the pages accordingly:
routes {
/register {
Application.setPage(Page::Register)
}
/login {
Application.setPage(Page::Login)
}
/ {
Application.setPage(Page::Home)
}
* {
Application.setPage(Page::NotFound)
}
}
And that is pretty much it 🎉 here you can find a repository with the actual
code:
https://github.com/mint-lang/mint-example-routing