1. Computed Properties
Allowing Native Bulma Navbars
Given the warning NOT to use external JS.
This builds off the the last version of counter organized.
Thanks to Szikszai Gusztáv, @gdotdesign on Mint-Gitter for code to replace bulma_navbar.js
with native Mint
code.
1.1. Setup
$ cp -r count_organized count_computed_properties
$ cd count_computed_properties
1.2. Strategy
-
Remove: js/bulma_navbar.js
-
Restore: mint.json to the original settings
-
Update: source/Layouts/Header.mint - to replace
js/bulma_navbar.js
using computed properties
1.3. Remove js/bulma_navbar.js
$ rm js/bulma_navbar.js
$ rmdir js
1.4. Restore mint.json
Restore mint.json
to its original setting.
{ "name": "route_n_properties", "source-directories": [ "source" ], "test-directories": [ "tests" ], "application": { "head": "assets/head.html" } }
1.5. Update Header with mint code
Update: source/Layouts/Header.mint
with computed properties
First lets understand what the JS code is doing:
document.addEventListener('DOMContentLoaded', () => {
// Get all "navbar-burger" elements
const $navbarBurgers = Array.prototype.slice.call(document.querySelectorAll('.navbar-burger'), 0);
// Check if there are any navbar burgers
if ($navbarBurgers.length > 0) {
// Add a click event on each of them
$navbarBurgers.forEach( el => {
el.addEventListener('click', () => {
// Get the target from the "data-target" attribute
const target = el.dataset.target;
const $target = document.getElementById(target);
// Toggle the "is-active" class on both the "navbar-burger" and the "navbar-menu"
el.classList.toggle('is-active');
$target.classList.toggle('is-active');
});
});
}
});
The most important thing to notice — despite all the rest of the code is:
// Toggle the "is-active" class on both the "navbar-burger" and the "navbar-menu"
el.classList.toggle('is-active');
$target.classList.toggle('is-active');
As the comment says — we need to toggle (add / remove) the bulma class is-active
to the elements with the classes: navbar-burger
and the navbar-menu
For example:
<a role="button" class="navbar-burger burger" aria-label="menu"
aria-expanded="false" data-target="navbarCounter">
// and when active:
<a role="button" class="navbar-burger burger is-active" aria-label="menu"
aria-expanded="false" data-target="navbarCounter">
And
<div id="navbarCounter" class="navbar-menu">
// and when active:
<div id="navbarCounter" class="navbar-menu is-active">
We need to do this toggle
when the navbar-burger
is clicked.
With this knowledge lets update Header
First we will create two computed properties (Computed properties are functions that work like properties, they are defined with the get keyword and no arguments.)
In our case we will use them to control the Bulma classes we need to update. For more info on propertied see: https://www.mint-lang.com/guide/reference/components/computed-properties
Here is the example of how to toggle with the navburger — we need 3 main parts:
-
a state to track if the menu is
active
(by default the state is NOT active) -
we need a function
navbarClick
to change the state when the menu is clicked -
we need the computed properties
burgerClass
andmenuClass
- which get automatically updated when theactive
state changes.
Below are the new code snippets needed:
state active : Bool = false
fun navbarClick (event : Html.Event) : Promise(Never, Void) {
next { active = !active }
}
get burgerClass : String {
if (active) {
"navbar-burger burger is-active"
} else {
"navbar-burger burger"
}
}
get menuClass : String {
if (active) {
"navbar-menu is-active"
} else {
"navbar-menu"
}
}
To integrate these we need to update the navbar-burger
and navbar-menu
:
<a role="button" class={burgerClass} onClick={navbarClick}
aria-label="menu" aria-expanded="false"
data-target="navbarCounter">
// and
<div id="navbarCounter" class={menuClass}>
Notice we integrate the computed properties with:
class={burgerClass}
// and
class={menuClass}
We only need the click activation on the navbar-burger - we integrate that with:
onClick={navbarClick}
Just like the button clicks on the counters.
So the full Header code now looks like:
component Header {
state active : Bool = false
fun navbarClick (event : Html.Event) : Promise(Never, Void) {
next { active = !active }
}
get burgerClass : String {
if (active) {
"navbar-burger burger is-active"
} else {
"navbar-burger burger"
}
}
get menuClass : String {
if (active) {
"navbar-menu is-active"
} else {
"navbar-menu"
}
}
fun render : Html {
<nav class="navbar is-light" role="navigation" aria-label="main navigation">
<div class="navbar-brand">
<a class="navbar-item" href="/">
<h1 id="title" class="navbar-item">
<{ "Counter" }>
</h1>
</a>
<a role="button" class={burgerClass} onClick={navbarClick}
aria-label="menu" aria-expanded="false"
data-target="navbarCounter">
<span aria-hidden="true"></span>
<span aria-hidden="true"></span>
<span aria-hidden="true"></span>
</a>
</div>
<div id="navbarCounter" class={menuClass}>
<div class="navbar-start">
<a class="navbar-item">
<{ "Docs" }>
</a>
<div class="navbar-item has-dropdown is-hoverable">
<a class="navbar-link">
<{ "More" }>
</a>
<div class="navbar-dropdown">
<a class="navbar-item">
<{ "About" }>
</a>
<a class="navbar-item">
<{ "Contact" }>
</a>
<hr class="navbar-divider"/>
<a class="navbar-item">
<{ "Report an issue" }>
</a>
</div>
</div>
</div>
<div class="navbar-end">
<div class="navbar-item">
<div class="buttons">
<a class="button is-primary">
<strong><{ "Sign up" }></strong>
</a>
<a class="button is-light">
<{ "Log in" }>
</a>
</div>
</div>
</div>
</div>
</nav>
}
}
1.6. Try it
start mint:
$ mint-lang start
every thing should still work!
Now, the project is free of JS.