Version: v0.6.0 - Beta.  We welcome contributors & feedback.  THanks!

To Do List (Example)

Overview 

This example will cover a form-based app that handles both GET and POST http methods.

Setup 

We assume you have created the starter app.

Within that app, create a new file pages/todo.tht.

Copy and paste each code snippet below into the file.

Main Function

The main function is called by default, when the page is requested via http GET (i.e. when a form is not submitted.)

function main() {
    $tasks = getTasks();
    Response.sendPage({
        body: bodyHtml($tasks),
        css: Css.plugin('base'),
    });
}

Data Functions

We will read and write the list of tasks to the user’s Session. The Session will be cleared when the user closes the browser tab.

(In a real app, you would read and write data to a database using the Db module.)

function getTasks() {
    // Default to an empty list if there are no tasks
    return Session.get('tasks', []);
}

function setTasks($tasks) {
    Session.set('tasks', $tasks);
}

function addTask($task) {
    $tasks = getTasks();
    tasks.push($task);
    setTasks($tasks);
}

function deleteTask($taskNum) {
    $tasks = getTasks();
    $tasks.remove($taskNum);
    setTasks($tasks);
}

Mode Functions

If the request has a POST parameter named mode, THT will automatically call the corresponding function instead of main.

The Input.post method reads the POST param and validates it per the rule defined in the 2nd argument.

// If POST mode='delete'
function modeDelete() {
    // 'taskNum' is an (i)nteger
    $taskNum = Input.post('taskNum', 'i');
    deleteTask($taskNum);

    return true;
}

// If POST mode='add'
function modeAdd() {
    // 'task' is a (s)tring
    $task = Input.post('task', 's');
    if $task {
        addTask($task);
    }
    return true;
}

Templates

The Web.formLink method creates a button that submits data (via a form with hidden fields), without the need for AJAX.

Styles are separated into a css template function. It will be minified and included inline.

function deleteButton($num) {
    $data = {
        mode: 'delete',
        taskNum: $num
    };
    return Web.formLink('X', url'/todo', $data, 'button-small');
}

template bodyHtml($tasks) {

    <main>
        {{ taskFormHtml() }}
        <hr />
        {{ taskListHtml($tasks) }}
    </>

    {{ pageCss() }}
}

template taskFormHtml() {

    <h2>New Task</>

    <form method="post" action="/todo">
        <input type="hidden" name="mode" value="add" />
        <input type="text" name="task" />
        <button type="submit">{{ Web.icon('plus') }} Add Task</>
    </>
}

template taskListHtml($tasks) {

    <h2>Tasks</>

    -- if !$tasks.length() {
        <i>No tasks.</>
    -- } else {
        -- foreach $tasks as $num, $task {
            <div class="task">
              {{ $task }}
              {{ deleteButton($num) }}
            </>
        -- }
    -- }
}

template pageCss() {

    .task {
        border-bottom: solid 1px #eee;
        padding: 1.2rem 1rem;
        position: relative;
    }
    .task form {
        position: absolute;
        right: 0;
        top: 0.8rem;
    }
}

See Also