5. Add your first interaction

Let the service create tasks

class TaskService extends Service<TaskService> {
    // Remove hardcoded tasks
    private _tasks: ITask[];

    constructor() {
        super();
        this._tasks = [];
    }
    
    public createTask(): void {
        let id = 0;
        if (this._tasks.length > 0){
            id = Math.max(...this._tasks.map(task => task.id)) + 1;
        }

        const newTask: ITask = {
            id: id,
            name: `Task ${id + 1}`,
        };

        this._tasks.push(newTask);
    }
}

Generate the component

npm run generate component components/new-task
# Creates src/app/components/new-task/new-task.component.ts|html|scss

Add the callback

import { Component, html } from '../../../core/index.js';
import { taskService } from '../../services/task/task.service.js';

const templateFn = () => html`__TEMPLATE_PLACEHOLDER__`;

export class NewTaskComponent extends Component {
    /* ... */
    private _newTask(): void {
        taskService.createTask();
    }
}

Bind the callback

<div class="new-task">
    <button data-event="click:_newTask">New Task</button>
</div>

The build checks the handler name against the component: a typo like click:_newTsk fails the build, pointing at that line of the template.

A little bit of styling

.new-task {
    padding: 2rem;
    button {
        background: #3C3C3A;
        color: #FAFAF9;
        padding: 1rem 1.5rem;
        font-size: 1.2rem;
        border-radius: 8px;
        &:hover {
            background: #2C2C2A;
        }
    }
}

Use the component in the view

/* ... */
import { NewTaskComponent } from '../../components/new-task/new-task.component.js';

export class TaskCatalogView extends View {
    /* ... */

    registerChildren(): Nutin.ComponentConfig[] {
        return [
            {
                selector: 'new-task',
                factory: (el) => new NewTaskComponent(el),
            },
            ...this.createCatalogComponents({ /* ... */ })
        ]
    }
}
<div class="task-catalog">
    <h1>Nutin Todo</h1>
    <!-- data-component attribute = "selector" target -->
    <div data-component="new-task"></div>
    <!-- ... -->
</div>

Make the view aware of task creation

Define an event

// src/app/globals.d.ts
declare namespace Nutin {
    interface AppEventMap {
        // to keep this lean, we'll reuse the same event for all operations
        'task-event': { taskId: number };
    }
}

Emit the event

/* ... */
import { AppEventBus } from '../../../core/index.js';

export class TaskService extends Service<TaskService> {
    /* ... */
    
    public createTask(): void {
        /* ... */
        AppEventBus.emit('task-event', { taskId: newTask.id });
    }
}

Listen to the event to re-render the view

export class TaskCatalogView extends View {
    constructor() {
        /* ... */
        this.listenToRenderEvents(['task-event']);
    }
}

Next step →