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:enterto listen to when the user hits the enter key.Listening to the
enterevent can be enabled by importing can-event-dom-enter/add-global/add-global.The default behavior creates a default value by using
new Defaultto initialize the value when aDefineMapproperty 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 //-> trueUse <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>