JavaScript like it should be
npm install piece-of-cake
or just include a script tag, like
<script src="https://unpkg.com/piece-of-cake"></script>
- Define your html like ever:
<body>
<input placeholder="what to to next?"/>
<button onclick="addTodo" disabled>Add</button>
<ul><!-- todo entries shall go here --></ul>
<script>
// functions like 'addTodo' and 'onChangeFilter' go here
</script>
</body>
- Extract your event handling functions into there own scope, where they belong:
class MyControllerClass {
addTodo() {
const input = document.getElementsByTagName("input")[0]
const list = document.getElementsByTagName("ul")[0]
const value = input.value
const li = document.createElement("li")
li.innerText = value
list.apendChild(li)
}
}
- Extend the PieceOfCake Controller to get access to some useful helper methods (this is optional)
class MyControllerClass extends PieceOfCake.Controller {
//...
}
- Simplify bindings to dom elements you need to access in your event handlers
<input placeholder="what to to next?"/>
<button onclick="addTodo" disabled>Add</button>
<ul data-id="todolist">
<!-- use a standard data tag here. Nothing special. No Side-effects -->
</ul>
class MyControllerClass extends {
get input() {
return this.find("input")
}
get list() {
return this.findByDataID("todolist")
}
addTodo() {
// ...
}
}
- Store your state in its own field, where it belongs:
class MyControllerClass extends {
get todos() {
return this._todos || [] // 'this._todos' is a kind of backing field. Nothing special. Just JavaScript
}
set todos(value) {
this._todos = value
}
addTodo() {
// ...
this.todos = [this.todos, text]
// ... update todo <ul>
}
}
- Connect your rendering logic to methods that update your state to keep your controller clean
class MyControllerClass extends {
set todos(value) {
this._todos = value
this._renderTodos()
}
addTodo() {
this.todos = [this.todos, text]
}
_renderTodos() {
this.list.innerHTML = ""
this.todos.forEach(text => {
const li = document.createElement("li")
li.innerText(text)
this.list.appendChild(li)
})
}
}
- Make your controller class visible to the library and connect it to a specific sub-tree of your dom it should control
PieceOfCake.controllerClasses.push(MyControllerClass)
<body data-controller="MyControllerClass">
<!-- Nothing special with the data-attribute. But you must call it 'controller', otherwise the library won't find it-- >
</body>
- Use optional field and element binding shorthands in your controller
class MyControllerClass extends {
static elements = {
input: "input", // this will bind 'this.input' to an element w/ data-id="input"
list: "todolist"
}
static fields = {
todos: { // this will create a getter and setter for the field 'todos'
defaultValue: [], // it creates a backing field w/ default Value []
set(value) { // define custom behavour after the backing field was updated here
this._renderTodos
}
}
}
}
Just look at the basic or advanced example script to get an idea of how things work.