/ PLAYGROUND

To-do app A Lucid-powered to-do app. This uses two components - a master component, and a child component for each 'to do' item.

Code

Components [?] Routes [?] Methods [?] Data [?]
<!-- COMPONENT MASTER -->
<div>
    <h1>Lucid to-do app!</h1>
    <p>
        <input id=newTodo placeholder='Add a new to-do...' data-lmodel=newTodo>
        <button onclick=addTodo>Add</button>
    </p>
    <ul>
        <Todo todo={{$value}} />
    </ul>
    <p id=markDone><button onclick=markDone disabled>Mark done</button></p>
</div>

<script>

//to-do items container
this.data.todos = [];

//set iteration on list
this.repeaters = {
    Todo: this.data.todos
};

//mark-all button available only if some to-dos added
this.conditionals = {
    '#mark-all-done': () => this.data.todos.length
};

//on 'add', add new to-do item
this.events.addTodo = () => {
    if (!this.data.newTodo) return;
    this.data.todos.push({
        task: this.data.newTodo,
        done: false
    });
    this.data.newTodo = '';
    this.reprocessReps();
    this.reprocessConds();
}; 

//router for messages from other components...
this.on('message', (comp, data) => {
    switch (data.msg) {
    
        //...from child 'Todo' component - reassess 'mark done' button disabled status
        case 'checkboxToggled':
            let btn = this.DOM.querySelector('#markDone button');
            data.state ? btn.removeAttribute('disabled') : btn.setAttribute('disabled', 1);
            break;
    }
});

//mark all items done
this.events.markDone = () => {
    this.message('todo', {msg: 'markDone'});
    this.DOM.querySelector('#markDone button').disabled = 1;
};
</script>

<style>
* { font-family: sans-serif; }
#newTodo { width: 200px; padding: 8px; }
button { background: salmon; padding: 9px 15px; color: white; border: none; border-radius:4px; font-weight: bold; cursor: pointer; position: relative; }
button[disabled] { opacity: .5; }
</style>

<!-- COMPONENT TODO -->
<li class=done-{{todo.done}}>
    <input type=checkbox>
    <span>✔</span>
    {{todo.task}}
    [
        <a class='mark done'>mark done</a>
        <a class='mark not-done'>mark not done</a>
    ]
</li>

<script>

//conditionally show either 'mark done' or 'mark not done' link - likewise done tick
this.conditionals = {
    '.mark.done': () => !this.data.todo.done,
    '.mark.not-done': () => this.data.todo.done,
    span: () => this.data.todo.done
};

//mark done/not done
this.DOM.onclick = evt => {
    if (!evt.target.matches('.mark')) return;
    this.data.todo.done = !this.data.todo.done;
    this.rc();
};

//checkbox for master's 'mark done' button - on toggle, tell parent to reassess whether button disabled or not
this.DOM.onchange = evt => {
    this.message('parent::*', {msg: 'checkboxToggled', state: evt.target.checked});
};

//router for messages from other components...
this.on('message', (comp, data) => {
    switch (data.msg) {
    
        //...'mark all' button clicked - mark item as done
        case 'markDone':
            let cb = this.DOM.querySelector('[type=checkbox]');
            if (!cb.checked) return;
            cb.checked = false;
            this.data.todo.done = true;
            this.rc();
            break;
    }
});
</script>

<style>
span { color: #0c0; }
</style>
//JS object of route data (optional)
{}
//JS object of filter methods (optional)
{}
//JS object of start data for master component
{}
Page help