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 aDefineMap
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>