Component Create page

Create todos (can-component)

The problem

Make it possible to create a todo, update the service layer and show the todo in the list of todos.

This functionality should be encapsulated by a <todo-create/> custom element.

What you need to know

  • The can-component presentation up to and including how to define a component.

  • A Component combines a custom tag name, stache view and a DefineMap ViewModel like:

    import Component from "can-component";
    import view from "./template.stache";
    const ViewModel = DefineMap.extend({
      ...      
    });
    
    Component.extend({
        tag: "some-component",
        view: view,
        ViewModel: ViewModel
    });
    
  • You can use on:enter to listen to when the user hits the enter key.

  • Listening to the enter event can be enabled by importing can-event-dom-enter/add-global/add-global.

  • The default behavior creates a default value by using new Default to initialize the value when a DefineMap property is read for the first time.

    const SubType = DefineMap.extend({})
    const Type = DefineMap.extend({
        property: {Default: SubType}
    })
    
    const map = new Type();
    map.property instanceof SubType //-> true
    
  • Use <can-import> to import a module from a template like:

    <can-import from="~/components/some-component/" />
    <some-component>
    

The solution

Click to see the solution

Create components/todo-create/todo-create.js as follows:

import {Component, enterEvent, domEvents} from "can";
import Todo from "~/models/todo";

domEvents.addEvent(enterEvent);

export default Component.extend({
    tag: "todo-create",
    view: `
        <input id="new-todo"
            placeholder="What needs to be done?"
            value:bind="todo.name"
            on:enter="createTodo()" />
    `,
    ViewModel: {
        todo: {
            Default: Todo
        },
        createTodo() {
            this.todo.save().then(function() {
                this.todo = new Todo();
            }.bind(this));
        }
    }
});

Update index.stache to the following:

<!-- index.stache -->
<can-import from="~/components/todo-create/" />
<section id="todoapp">
    <header id="header">
        <h1>{{ this.appName }}</h1>
        <todo-create/>
    </header>
    <section id="main" class="">
        <input id="toggle-all" type="checkbox">
        <label for="toggle-all">Mark all as complete</label>
        <ul id="todo-list">
            {{# for(todo of this.todosList) }}
                <li class="todo {{# if(todo.complete) }}completed{{/ if }}
                    {{# if(todo.isDestroying()) }}destroying{{/ if }}">
                    <div class="view">
                        <input class="toggle" type="checkbox"
                            checked:bind="todo.complete"
                            on:change="todo.save()"
                            disabled:from="todo.isSaving()" />
                        <label>{{ todo.name }}</label>
                        <button class="destroy" on:click="todo.destroy()"></button>
                    </div>
                    <input class="edit" type="text" value="{{ todo.name }}" />
                </li>
            {{/ for }}
        </ul>
    </section>
    <footer id="footer" class="">
        <span id="todo-count">
            <strong>{{ this.todosList.active.length }}</strong> items left
        </span>
        <ul id="filters">
            <li>
                <a class="selected" href="#!">All</a>
            </li>
            <li>
                <a href="#!active">Active</a>
            </li>
            <li>
                <a href="#!completed">Completed</a>
            </li>
        </ul>
        <button id="clear-completed">
            Clear completed ({{ this.todosList.complete.length }})
        </button>
    </footer>
</section>