can
Version:
MIT-licensed, client-side, JavaScript framework that makes building rich web applications easy.
1,380 lines (1,073 loc) • 79.5 kB
HTML
<!DOCTYPE html>
<!--####################################################################
THIS IS A GENERATED FILE -- ANY CHANGES MADE WILL BE OVERWRITTEN
INSTEAD CHANGE:
source: [object Object]
@page guides/todomvc
######################################################################## -->
<html lang="en">
<head>
<meta charset="utf-8">
<title>CanJS - TodoMVC Guide</title>
<meta name="viewport" content="width=device-width, initial-scale=1, maximum-scale=1, user-scalable=no">
<link rel="stylesheet" type="text/css" href="../static/bundles/bit-docs-site/static.css">
<link rel="shortcut icon" sizes="16x16 24x24 32x32 48x48 64x64" href="/docs/images/canjs_favicon.ico">
<link rel="apple-touch-icon" sizes="57x57" href="../../docs/images/canjs_favicon_57x57.png">
<link rel="apple-touch-icon-precomposed" sizes="57x57" href="../../docs/images/canjs_favicon_57x57.png">
<link rel="apple-touch-icon" sizes="72x72" href="../../docs/images/canjs_favicon_72x72.png">
<link rel="apple-touch-icon" sizes="114x114" href="../../docs/images/canjs_favicon_114x114.png">
<link rel="apple-touch-icon" sizes="120x120" href="../../docs/images/canjs_favicon_128x128.png">
<link rel="apple-touch-icon" sizes="144x144" href="../../docs/images/canjs_favicon_144x144.png">
<link rel="apple-touch-icon" sizes="152x152" href="../../docs/images/canjs_favicon_152x152.png">
<meta content="yes" name="apple-mobile-web-app-capable">
<meta name="apple-mobile-web-app-status-bar-style" content="white-translucent">
<script>
(function(i,s,o,g,r,a,m){i['GoogleAnalyticsObject']=r;i[r]=i[r]||function(){
(i[r].q=i[r].q||[]).push(arguments)},i[r].l=1*new Date();a=s.createElement(o),
m=s.getElementsByTagName(o)[0];a.async=1;a.src=g;m.parentNode.insertBefore(a,m)
})(window,document,'script','https://www.google-analytics.com/analytics.js','ga');
ga('create', 'UA-2302003-11', 'auto');
ga('send', 'pageview');
</script>
</head>
<body>
<input type="checkbox" id="nav-trigger" class="nav-trigger"/>
<label for="nav-trigger">Menu</label>
<div id="everything">
<div id="left" class="column">
<div class="top-left">
<div class="brand">
<div class="logo">
<a href="../../index.html" alt="CanJS"></a>
<div class="dropdown project-dropdown">
<a href="https://donejs.com/">DoneJS</a>
<a href="http://stealjs.com/">StealJS</a>
<a href="http://jquerypp.com/">jQuery ++</a>
<a href="https://funcunit.com/">FuncUnit</a>
<a href="http://documentjs.com/">DocumentJS</a>
</div>
</div>
<div class="version">
<div class="version-number">
3.0.0
</div>
<div class="dropdown version-dropdown">
<a href="https://v2.canjs.com">2.3.27</a>
</div>
</div>
</div>
<div class="search-bar">
<p>
</p>
</div>
</div>
<div class="bottom-left">
<div class="social-side-container">
<ul class="social-side">
<li>
<a class="header-mobile github" href="https://github.com/canjs/canjs" target="_blank"><img class="social-icon-small" src="../../docs/images/github.png">Github</a>
</li>
<li>
<a class="header-mobile twitter" href="https://twitter.com/canjs" target="_blank"><img class="social-icon-small" src="../../docs/images/twitter.png">Twitter</a>
</li>
</ul>
<ul class="social-side">
<li>
<a class="header-mobile" href="https://gitter.im/canjs/canjs" target="_blank">Chat</a>
</li>
<li>
<a class="header-mobile" href="http://forums.donejs.com/c/canjs" target="_blank">Forum</a>
</li>
</ul>
</div>
<ul>
<li class="
parent
expanded">
<a class="page"
href="../guides.html"
title="Welcome to CanJS! These guides are here to help you develop and improve your relationship with CanJS. After all, picking a JavaScript framework is a commitment. We want CanJS to be the
framework you marry. This page helps you know how advance through the different stages of this
relationship:">
Guides
</a>
<ul>
<li>
<span>introduction</span>
<ul>
<li class="
">
<a class="page"
href="mission.html"
title="Learn about CanJS's mission, why it matters, and how we've worked (and will keep working) to accomplish it.">
Mission
</a>
</li>
<li class="
">
<a class="page"
href="technical.html"
title="">
Technical Highlights
</a>
</li>
<li class="
">
<a class="page"
href="who-uses-canjs.html"
title="">
Who uses CanJS?
</a>
</li>
</ul>
</li>
<li>
<span>experiment</span>
<ul>
<li class="
">
<a class="page"
href="chat.html"
title="This guide walks through building real time chat application with CanJS's Core libraries. It takes about 30 minutes to complete.">
Chat Guide
</a>
</li>
<li class="current
parent
expanded">
<a class="page"
href="todomvc.html"
title="This guide walks through building a slightly modified version of TodoMVC with CanJS's Core libraries and can-fixture. It takes about 1 hour to complete.">
TodoMVC Guide
</a>
</li>
<li class="
">
<a class="page"
href="atm.html"
title="This guide walks through building and testing an ATM application with CanJS's
Core libraries. It teaches how to do test driven development (TDD)
and manage complex state. It takes about 2 hours to complete.">
ATM Guide
</a>
</li>
<li class="
">
<a class="page"
href="setup.html"
title="CanJS is packaged in multiple ways so that it can fit into any development workflow. Learn how to setup CanJS in different environments.">
Setting up CanJS
</a>
</li>
</ul>
</li>
<li>
<span>commitment</span>
<ul>
<li class="
">
<a class="page"
href="api.html"
title="This page walks through how to use and understand CanJS's API documentation.">
API Guide
</a>
</li>
<li class="
">
<a class="page"
href="examples.html"
title="">
Examples
</a>
</li>
<li class="
">
<a class="page"
href="../roadmap.html"
title="Learn about CanJS's future plans and how we make them, and how you can influence them.">
Roadmap
</a>
</li>
<li class="
">
<a class="page"
href="../migrate-3.html"
title="">
Migrating to 3.0
</a>
</li>
</ul>
</li>
<li>
<span>contribute</span>
<ul>
<li class="
">
<a class="page"
href="contributing/bug-report.html"
title="Learn how to submit a bug report.">
Bug Report
</a>
</li>
<li class="
">
<a class="page"
href="contributing/code.html"
title="Learn how contribute a code change to CanJS.">
Code
</a>
</li>
<li class="
">
<a class="page"
href="contributing/documentation.html"
title="Learn how to improve CanJS's site and documentation.">
Documentation
</a>
</li>
<li class="
">
<a class="page"
href="contributing/evangelism.html"
title="Learn about resources that can help you spread the word about CanJS.">
Evangelism
</a>
</li>
<li class="
">
<a class="page"
href="contributing/feature-suggestion.html"
title="Learn how to suggest a feature.">
Feature Suggestion
</a>
</li>
<li class="
">
<a class="page"
href="contributing/releases.html"
title="Release and hosting information for CanJS maintainers.">
Releases
</a>
</li>
</ul>
</li>
</ul>
</li>
<li class="
">
<a class="page"
href="../can-core.html"
title="The best, most hardened and generally useful libraries in CanJS.">
Core
</a>
</li>
<li class="
">
<a class="page"
href="../can-ecosystem.html"
title="Useful libraries that extend or add important features to the core collection.">
Ecosystem
</a>
</li>
<li class="
">
<a class="page"
href="../can-infrastructure.html"
title="Utility libraries that power the core and ecosystem collection.">
Infrastructure
</a>
</li>
<li class="
">
<a class="page"
href="../can-legacy.html"
title="Former libraries that we still accept patches for, but are not under active development.">
Legacy
</a>
</li>
</ul>
</div>
</div>
<div id="right" class="column">
<div class="top-right">
<div class="top-right-top">
<ul class="top-right-bitovi">
<li class="dropdown">
<a href="http://bitovi.com" class="bitovi icon-bits">Bitovi</a>
<ul class="dropdown-menu">
<li><a href="http://bitovi.com">Bitovi.com</a></li>
<li><a href="http://bitovi.com/blog/">Blog</a></li>
<li><a href="http://bitovi.com/consulting/">Consulting</a></li>
<li><a href="http://bitovi.com/training/">Training</a></li>
<li><a href="http://bitovi.com/open-source/">Open Source</a></li>
</ul>
</li>
</ul>
<div class="brand">
<div class="logo">
<a href="../../index.html" alt="CanJS"></a>
</div>
</div>
<ul class="top-right-links">
<li>
<a href="https://gitter.im/canjs/canjs">Chat</a>
</li>
<li>
<a href="http://forums.donejs.com/c/canjs">Forum</a>
</li>
<li>
<a class="github-button nav-social" href="https://github.com/canjs/canjs" data-count-href="/canjs/canjs/stargazers" data-count-api="/repos/canjs/canjs#stargazers_count">Star</a>
</li>
<li>
<a href="https://twitter.com/canjs" class="twitter-follow-button nav-social" data-show-count="true" data-show-screen-name="false">Follow @canjs</a><script async src="//platform.twitter.com/widgets.js" charset="utf-8"></script>
</li>
</ul>
</div>
<div class="breadcrumb">
<li><a href="../../index.html">CanJS</a></li> /
<li><a href="../guides.html">Guides</a></li> /
<li><a href="todomvc.html">TodoMVC Guide</a></li>
<li class="breadcrumb-dropdown">/ <a> On this page</a>
<ul class="on-this-page"></ul>
</li>
<div class="nav-toggle" title="Back to top"></div>
</div>
</div>
<div class="bottom-right">
<article>
<section class="title">
<div class="page-type">
<h1>TodoMVC Guide</h1>
<div>page</div>
</div>
<section class="description">
<p>This guide walks through building a slightly modified version of <a href="http://todomvc.com/">TodoMVC</a> with CanJS's <a href="../can-core.html" title="The best, most hardened and generally useful libraries in CanJS.">Core libraries</a> and <a href="../can-fixture.html" title="can-fixture intercepts an AJAX request and simulates the response with a file or function.">can-fixture</a>. It takes about 1 hour to complete.</p>
</section>
</section>
<section class="on-this-page-table">
</section>
<section class="title-footer">
<ul class="title-links">
<!-- <li><a href="#">docco</a></li> -->
<li><a href="//github.com/canjs/canjs/tree/v3.0.0/docs/can-guides/experiment/todomvc/todomvc.md">source</a></li>
<!-- <li><a href="#">download</a></li> -->
<!-- <li><a href="#">tests</a></li> -->
</ul>
</section>
<section class="body">
<h2>Setup</h2>
<p>The easiest way to get started is to clone the following JSBin by clicking the <strong>JS Bin</strong> button on the top left:</p>
<p><a class="jsbin-embed" href="http://jsbin.com/sasuje/11/embed?html,output">JS Bin on jsbin.com</a></p>
<p>The JSBin starts
with the static HTML and CSS a designer might turn over to a JS developer. We will be
adding all the JavaScript functionality.</p>
<p>The JSBin also loads <a href="https://unpkg.com/can/dist/global/can.all.js">can.all.js</a>, which is a script that includes CanJS all of CanJS core, ecosystem, legacy and infrastructure libraries under a
single global <code>can</code> namespace.</p>
<p>Generally speaking, you should not use the global can script and instead
should import things directly with a module loader like <a href="http://stealjs.com">StealJS</a>,
WebPack or Browserify. In a real app your code will look like:</p>
<pre><code class="language-js">var DefineMap = require("can-define/map/map");
var DefineList = require("can-define/list/list");
var Todo = DefineMap.extend({ ... });
Todo.List = DefineList.extend({ ... });
</code></pre>
<p>Not:</p>
<pre><code class="language-js">var Todo = can.DefineMap.extend({ ... });
Todo.List = can.DefineList.extend({ ... });
</code></pre>
<p>Read <a href="setup.html" title="CanJS is packaged in multiple ways so that it can fit into any development workflow. Learn how to setup CanJS in different environments.">Setting up CanJS</a> on how to setup CanJS in a real app.</p>
<h2>Create and render the template</h2>
<p>In this section, we will render the markup in a <a href="../can-stache.html" title="Live binding Mustache and Handlebars-compatible templates.">can-stache</a> live bound template.</p>
<p>Update the <code>HTML</code> tab to have a <code><script></code> tag around the html content.</p>
<pre><code class="language-html"><!DOCTYPE html>
<html>
<head>
<meta name="description" content="TodoMVC Guide 3.0 Start">
<meta charset="utf-8">
<meta name="viewport" content="width=device-width">
<title>JS Bin</title>
</head>
<body>
<script type="text/stache" id="todomvc-template">
<section id="todoapp">
<header id="header">
<h1>todos</h1>
<input id="new-todo" placeholder="What needs to be done?">
</header>
<section id="main" class="">
<input id="toggle-all" type="checkbox">
<label for="toggle-all">Mark all as complete</label>
<ul id="todo-list">
<li class="todo">
<div class="view">
<input class="toggle" type="checkbox">
<label>Do the dishes</label>
<button class="destroy"></button>
</div>
<input class="edit" type="text" value="Do the dishes">
</li>
<li class="todo completed">
<div class="view">
<input class="toggle" type="checkbox">
<label>Mow the lawn</label>
<button class="destroy"></button>
</div>
<input class="edit" type="text" value="Mow the lawn">
</li>
<li class="todo editing">
<div class="view">
<input class="toggle" type="checkbox">
<label>Pick up dry cleaning</label>
<button class="destroy"></button>
</div>
<input class="edit" type="text" value="Pick up dry cleaning">
</li>
</ul>
</section>
<footer id="footer" class="">
<span id="todo-count">
<strong>2</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 (1)
</button>
</footer>
</section>
</script>
<script src="https://code.jquery.com/jquery-2.2.4.js"></script>
<script src="https://unpkg.com/can/dist/global/can.all.js"></script>
</body>
</html>
</code></pre>
<p><span line-highlight='11,67,only'></span>
Update the <code>JavaScript</code> tab to:</p>
<ul>
<li>Use <a href="../can-stache.from.html" title="Return a template loaded from an element.">can-stache.from</a> to load the contents of the <code><script></code> tag as
a <a href="../can-stache.renderer.html" title="A function returned by can-stache that renders a template into an html documentFragment.">template renderer function</a>.</li>
<li>Render the template with an empty object into a <a href="https://developer.mozilla.org/en-US/docs/Web/API/DocumentFragment">document fragment</a>.</li>
<li>Insert the fragment into the document's <code><body></code> element.</li>
</ul>
<p>To load and render this template, and add the result to the
body, add the following to the <code>JavaScript</code> tab:</p>
<pre><code class="language-js">var template = can.stache.from("todomvc-template");
var frag = template({});
document.body.appendChild(frag);
</code></pre>
<p><span line-highlight='1-3,only'></span></p>
<p>When complete, you should see the same content as before. Only now, it's
rendered with a live-bound stache template. The live binding means that
when the template's data is changed, it will update automatically. We'll see
that in the next step.</p>
<h2>Define the todos type and show the active and complete count.</h2>
<p>In this section, we will:</p>
<ul>
<li>List todos from a list of todos.</li>
<li>Show the number of active (<code>complete === true</code>) and complete todos.</li>
<li>Connect a todo's <code>complete</code> property to a checkbox so that when
we toggle the checkbox the number of active and complete todos changes.</li>
</ul>
<p>Update the <code>JavaScript</code> tab to:</p>
<ul>
<li>Define a <code>Todo</code> type with <a href="../can-define/map/map.html" title="Create observable objects.">can-define/map/map</a>.</li>
<li>Define a <code>Todo.List</code> type along with an <code>active</code> and <code>complete</code> property with <a href="../can-define/list/list.html" title="Create observable lists.">can-define/list/list</a>.</li>
<li>Create a list of todos and pass those to the template.</li>
</ul>
<pre><code class="language-js">var Todo = can.DefineMap.extend({
id: "string",
name: "string",
complete: {type: "boolean", value: false}
});
Todo.List = can.DefineList.extend({
"#": Todo,
get active(){
return this.filter({complete: false});
},
get complete(){
return this.filter({complete: true});
}
});
var todos = new Todo.List([
{ id: 5, name: "mow lawn", complete: false },
{ id: 6, name: "dishes", complete: true },
{ id: 7, name: "learn canjs", complete: false }
]);
var template = can.stache.from("todomvc-template");
var frag = template({todos: todos});
document.body.appendChild(frag);
</code></pre>
<p><span line-highlight='1-21,24,only'></span>
Update the <code>HTML</code> tab to:</p>
<ul>
<li>Use <a href="../can-stache.helpers.each.html" title="">{{#each expression}}</a> to loop through every todo.</li>
<li>Add <code>completed</code> to the <code><li></code>'s <code>className</code> if the <code><li></code>'s todo is complete.</li>
<li>Use <a href="../can-stache-bindings.twoWay.html" title="Two-way bind a value in the viewModel or the element to the parent scope.">{(two-way)}</a> to two-way bind the checkbox's <code>checked</code> property to its todo's <code>complete</code> property.</li>
<li>Use <a href="../can-stache.tags.escaped.html" title="Insert the value of the expression into the output of the template.">{{expression}}</a> to insert the value todo's <code>name</code> as the content of the <code><label></code> and
<code>value</code> of the text <code><input/></code>.</li>
<li>Insert the active and complete number of todos.</li>
</ul>
<pre><code class="language-html"><!DOCTYPE html>
<html>
<head>
<meta name="description" content="TodoMVC Guide 3.0 - Create and render the template">
<meta charset="utf-8">
<meta name="viewport" content="width=device-width">
<title>JS Bin</title>
</head>
<body>
<script type="text/stache" id="todomvc-template">
<section id="todoapp">
<header id="header">
<h1>todos</h1>
<input id="new-todo" placeholder="What needs to be done?">
</header>
<section id="main" class="">
<input id="toggle-all" type="checkbox">
<label for="toggle-all">Mark all as complete</label>
<ul id="todo-list">
{{#each todos}}
<li class="todo {{#if complete}}completed{{/if}}">
<div class="view">
<input class="toggle" type="checkbox" {($checked)}="complete">
<label>{{name}}</label>
<button class="destroy"></button>
</div>
<input class="edit" type="text" value="{{name}}"/>
</li>
{{/each}}
</ul>
</section>
<footer id="footer" class="">
<span id="todo-count">
<strong>{{todos.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 ({{todos.complete.length}})
</button>
</footer>
</section>
</script>
<script src="https://code.jquery.com/jquery-2.2.4.js"></script>
<script src="https://unpkg.com/can/dist/global/can.all.js"></script>
</body>
</html>
</code></pre>
<p><span line-highlight='21-30,35,49,only'></span>
When complete, you should be able to toggle the checkboxes and see the number of
items left and the completed count change automatically. This is because
<a href="../can-stache.html" title="Live binding Mustache and Handlebars-compatible templates.">can-stache</a> is able to listen for changes in observables like <a href="../can-define/map/map.html" title="Create observable objects.">can-define/map/map</a>,
<a href="../can-define/list/list.html" title="Create observable lists.">can-define/list/list</a> and <a href="../can-compute.html" title="Create an observable value.">can-compute</a>.</p>
<video controls>
<source src="../../docs/can-guides/experiment/todomvc/2-items-left/completed.mp4" type="video/mp4">
<source src="../../docs/can-guides/experiment/todomvc/2-items-left/completed.webm" type="video/webm">
</video>
<h2>Get todos from the server</h2>
<p>In this section, we will:</p>
<ul>
<li>Load todos from a restful service.</li>
<li>Fake that restful service.</li>
</ul>
<p>Update the <code>JavaScript</code> tab to:</p>
<ul>
<li>Define what the restful service layer's parameters are with <a href="../can-set.html" title="can-set is a utility for comparing sets that are represented by the parameters commonly passed to service requests.">can-set</a>.</li>
<li>Create a fake data store that is initialized with data for 3 todos with <a href="../can-fixture.store.html" title="">store</a>.</li>
<li>Trap AJAX requests to <code>"/api/todos"</code> and provide responses with the data from the fake data store with <a href="../can-fixture.html" title="can-fixture intercepts an AJAX request and simulates the response with a file or function.">can-fixture</a>.</li>
<li>Connect the <code>Todo</code> and <code>Todo.List</code> types to the restful <code>"/api/todos"</code> endpoint using <a href="../can-connect/can/super-map/super-map.html" title="Create connection with many of the best behaviors in can-connect and hook it up to
a map.">can-connect/can/super-map/super-map</a>. This allows you to load, create, update, and destroy todos
on the server.</li>
<li>Use <a href="../can-connect/can/map/map.getList.html" title="Gets a list of instances of the map type.">getList</a> to load a list of all todos on the server. The result
of <code>getList</code> is a <a href="https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Promise">Promise</a> that resolves to a <code>Todo.List</code> with the todos returned from the fake data store. That <code>Promise</code>
is passed to the template as <code>todosPromise</code>.</li>
</ul>
<pre><code class="language-js">var todoAlgebra = new can.set.Algebra(
can.set.props.boolean("complete"),
can.set.props.id("id"),
can.set.props.sort("sort")
);
var todoStore = can.fixture.store([
{ name: "mow lawn", complete: false, id: 5 },
{ name: "dishes", complete: true, id: 6 },
{ name: "learn canjs", complete: false, id: 7 }
], todoAlgebra);
can.fixture("/api/todos", todoStore);
can.fixture.delay = 1000;
var Todo = can.DefineMap.extend({
id: "string",
name: "string",
complete: {type: "boolean", value: false}
});
Todo.List = can.DefineList.extend({
"#": Todo,
get active(){
return this.filter({complete: false});
},
get complete(){
return this.filter({complete: true});
}
});
can.connect.superMap({
url: "/api/todos",
Map: Todo,
List: Todo.List,
name: "todo",
algebra: todoAlgebra
});
var template = can.stache.from("todomvc-template");
var frag = template({todosPromise: Todo.getList({})});
document.body.appendChild(frag);
</code></pre>
<p><span line-highlight='1-15,33-39,42,only'></span>
Update the <code>HTML</code> tab to:</p>
<ul>
<li>Use <a href="../can-stache.helpers.each.html" title="">{{#each expression}}</a> to loop through the promise's resolved value, which
is the list of todos returned by the server.</li>
<li>Read the active and completed number of todos from the promise's resolved value.</li>
</ul>
<pre><code class="language-html"><!DOCTYPE html>
<html>
<head>
<meta name="description" content="TodoMVC Guide 3.0 - Create the todos type and get items left working">
<meta charset="utf-8">
<meta name="viewport" content="width=device-width">
<title>JS Bin</title>
</head>
<body>
<script type="text/stache" id="todomvc-template">
<section id="todoapp">
<header id="header">
<h1>todos</h1>
<input id="new-todo" placeholder="What needs to be done?">
</header>
<section id="main" class="">
<input id="toggle-all" type="checkbox">
<label for="toggle-all">Mark all as complete</label>
<ul id="todo-list">
{{#each todosPromise.value}}
<li class="todo {{#if complete}}completed{{/if}}">
<div class="view">
<input class="toggle" type="checkbox" {($checked)}="complete">
<label>{{name}}</label>
<button class="destroy"></button>
</div>
<input class="edit" type="text" value="{{name}}"/>
</li>
{{/each}}
</ul>
</section>
<footer id="footer" class="">
<span id="todo-count">
<strong>{{todosPromise.value.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 ({{todosPromise.value.complete.length}})
</button>
</footer>
</section>
</script>
<script src="https://code.jquery.com/jquery-2.2.4.js"></script>
<script src="https://unpkg.com/can/dist/global/can.all.js"></script>
</body>
</html>
</code></pre>
<p><span line-highlight='21,35,49,only'></span>
When complete, you'll notice a 1 second delay before seeing the list of todos as
they load for the first time from the fixtured data store. On future page reloads, the
list of todos will load immediately. This is because <a href="../can-connect/can/super-map/super-map.html" title="Create connection with many of the best behaviors in can-connect and hook it up to
a map.">can-connect/can/super-map/super-map</a> ads the <a href="../can-connect/fall-through-cache/fall-through-cache.html" title="A fall through cache that checks another cacheConnection.">can-connect/fall-through-cache/fall-through-cache</a> behavior. The
<a href="../can-connect/fall-through-cache/fall-through-cache.html" title="A fall through cache that checks another cacheConnection.">can-connect/fall-through-cache/fall-through-cache</a> behavior stores loaded data in
localStorage. Future requests will hit localStorage for data first, present that data
to the user, before making a request to the server and updating the original data with
any changes. Use <code>localStorage.clear()</code> to see the difference.</p>
<h2>Destroy todos</h2>
<p>In this section, we will:</p>
<ul>
<li>Delete a todo on the server when its destroy button is clicked.</li>
<li>Remove the todo from the page after it's deleted.</li>
</ul>
<p>Update the <code>HTML</code> tab to:</p>
<ul>
<li>Add <code>destroying</code> to the <code><li></code>'s <code>className</code> if the <code><li></code>'s todo is being destroyed using <a href="../can-connect/can/map/map.prototype.isDestroying.html" title="Returns if the map is currently being destroyed.">isDestroying</a>.</li>
<li>Call the <code>todo</code>'s <a href="../can-connect/can/map/map.prototype.destroy.html" title="Delete's the instance with the connection.">destroy</a> method when the <code><button></code> is clicked using <a href="../can-stache-bindings.event.html" title="Response to events on elements or component ViewModels.">(event)</a>.</li>
</ul>
<pre><code class="language-html"><!DOCTYPE html>
<html>
<head>
<meta name="description" content="TodoMVC Guide 3.0 - Destroy todos">
<meta charset="utf-8">
<meta name="viewport" content="width=device-width">
<title>JS Bin</title>
</head>
<body>
<script type="text/stache" id="todomvc-template">
<section id="todoapp">
<header id="header">
<h1>todos</h1>
<input id="new-todo" placeholder="What needs to be done?">
</header>
<section id="main" class="">
<input id="toggle-all" type="checkbox">
<label for="toggle-all">Mark all as complete</label>
<ul id="todo-list">
{{#each todosPromise.value}}
<li class="todo {{#if complete}}completed{{/if}}
{{#if isDestroying}}destroying{{/if}}">
<div class="view">
<input class="toggle" type="checkbox" {($checked)}="complete">
<label>{{name}}</label>
<button class="destroy" ($click)="destroy()"></button>
</div>
<input class="edit" type="text" value="{{name}}"/>
</li>
{{/each}}
</ul>
</section>
<footer id="footer" class="">
<span id="todo-count">
<strong>{{todosPromise.value.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 ({{todosPromise.value.complete.length}})
</button>
</footer>
</section>
</script>
<script src="https://code.jquery.com/jquery-2.2.4.js"></script>
<script src="https://unpkg.com/can/dist/global/can.all.js"></script>
</body>
</html>
</code></pre>
<p><span line-highlight='22-23,27,only'></span>
When complete, you should be able to delete a todo by clicking its delete button. After
clicking the todo, its name will turn red and italic. Once deleted the todo will be
automatically removed from the page.</p>
<p>The deleted todo is automatically removed from the page because <a href="../can-connect/can/super-map/super-map.html" title="Create connection with many of the best behaviors in can-connect and hook it up to
a map.">can-connect/can/super-map/super-map</a> ads the <a href="../can-connect/real-time/real-time.html" title="Update lists to include or exclude instances based
on set logic.">can-connect/real-time/real-time</a> behavior. The
<a href="../can-connect/real-time/real-time.html" title="Update lists to include or exclude instances based
on set logic.">can-connect/real-time/real-time</a> behavior automatically updates lists (like <code>Todo.List</code>) when instances
are created, updated or destroyed. If you've created the right <a href="../can-set.Algebra.html" title="Perform set logic with an awareness of how certain properties represent a set.">Algebra</a>, you
shouldn't have to manage lists yourself.</p>
<p>Finally, if you refresh the page after deleting, you'll notice the page temporarily shows fewer items.
This is because the fall through cache's data is shown before the response from fixtured data store
is used.</p>
<video controls>
<source src="../../docs/can-guides/experiment/todomvc/4-destroy/completed.mp4" type="video/mp4">
<source src="../../docs/can-guides/experiment/todomvc/4-destroy/completed.webm" type="video/webm">
</video>
<h2>Create todos</h2>
<p>In this section, we will:</p>
<ul>
<li>Create a custom element that can create todos on the server.</li>
<li>Use that custom element.</li>
</ul>
<p>Update the <code>JavaScript</code> tab to:</p>
<ul>
<li>Use <a href="../can-define/map/map.html" title="Create observable objects.">can-define/map/map</a> to create a <code>TodoCreateVM</code> view model with:
<ul>
<li>A <code>todo</code> property that holds a new <code>Todo</code> instance.</li>
<li>A <code>createTodo</code> method that <a href="../can-connect/can/map/map.prototype.save.html" title="Persists the map's data to the connection.">save</a>s the <code>Todo</code> instance
and replaces it with a new one once saved.</li>
</ul></li>
<li>Use <a href="../can-component.html" title="Create a custom element that can be used to manage widgets or application logic.">can-component</a> to create a custom <code><todo-create></code> component that renders the <code>todo-create-template</code> template with an instance of the <code>TodoCreateVM</code>.</li>
</ul>
<pre><code class="language-js">var todoAlgebra = new can.set.Algebra(
can.set.props.boolean("complete"),
can.set.props.id("id"),
can.set.props.sort("sort")
);
var todoStore = can.fixture.store([
{ name: "mow lawn", complete: false, id: 5 },
{ name: "dishes", complete: true, id: 6 },
{ name: "learn canjs", complete: false, id: 7 }
], todoAlgebra);
can.fixture("/api/todos", todoStore);
can.fixture.delay = 1000;
var Todo = can.DefineMap.extend({
id: "string",
name: "string",
complete: {type: "boolean", value: false}
});
Todo.List = can.DefineList.extend({
"#": Todo,
get active(){
return this.filter({complete: false});
},
get complete(){
return this.filter({complete: true});
}
});
can.connect.superMap({
url: "/api/todos",
Map: Todo,
List: Todo.List,
name: "todo",
algebra: todoAlgebra
});
var TodoCreateVM = can.DefineMap.extend({
todo: {Value: Todo},
createTodo: function(){
this.todo.save().then(function(){
this.todo = new Todo();
}.bind(this));
}
});
can.Component.extend({
tag: "todo-create",
view: can.stache.from("todo-create-template"),
ViewModel: TodoCreateVM
});
var template = can.stache.from("todomvc-template");
var frag = template({todosPromise: Todo.getList({})});
document.body.appendChild(frag);
</code></pre>
<p><span line-highlight='42-55,only'></span>
Update the <code>HTML</code> tab to:</p>
<ul>
<li>Create the <code>todo-create-template</code> that:
<ul>
<li>Updates the <code>todo</code>'s <code>name</code> with the <code><input></code>'s <code>value</code> using <a href="../can-stache-bindings.twoWay.html" title="Two-way bind a value in the viewModel or the element to the parent scope.">{(two-way)}</a>.</li>
<li>Calls <code>createTodo</code> when the <code>enter</code> key is pressed using <a href="../can-stache-bindings.event.html" title="Response to events on elements or component ViewModels.">(event)</a>.</li>
</ul></li>
<li>Use <code><todo-create/></code></li>
</ul>
<pre><code class="language-html"><!DOCTYPE html>
<html>
<head>
<meta name="description" content="TodoMVC Guide 3.0 - Create todos">
<meta charset="utf-8">
<meta name="viewport" content="width=device-width">
<title>JS Bin</title>
</head>
<body>
<script type='text/stache' id='todo-create-template'>
<input id="new-todo"
placeholder="What needs to be done?"
{($value)}="todo.name"
($enter)="createTodo()"/>
</script>
<script type="text/stache" id="todomvc-template">
<section id="todoapp">
<header id="header">
<h1>todos</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">
{{#each todosPromise.value}}
<li class="todo {{#if complete}}completed{{/if}}
{{#if isDestroying}}destroying{{/if}}">
<div class="view">
<input class="toggle" type="checkbox" {($checked)}="complete">
<label>{{name}}</label>
<button class="destroy" ($click)="destroy()"></button>
</div>
<input class="edit" type="text" value="{{name}}"/>
</li>
{{/each}}
</ul>
</section>
<footer id="footer" class="">
<span id="todo-count">
<strong>{{todosPromise.value.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 ({{todosPromise.value.complete.length}})
</button>
</footer>
</section>
</script>
<script src="https://code.jquery.com/jquery-2.2.4.js"></script>
<script src="https://unpkg.com/can/dist/global/can.all.js"></script>
</body>
</html>
</code></pre>
<p><span line-highlight='11-16,22,only'></span>
When complete, you will be able to create a todo by typing the name of the todo and pressing
<code>enter</code>. Notice that the new todo automatically appears in the list of todos. This
is also because <a href="../can-connect/can/super-map/super-map.html" title="Create connection with many of the best behaviors in can-connect and hook it up to
a map.">can-connect/can/super-map/super-map</a> adds the <a href="../can-connect/real-time/real-time.html" title="Update lists to include or exclude instances based
on set logic.">can-connect/real-time/real-time</a> behavior. The
<a href="../can-connect/real-time/real-time.html" title="Update lists to include or exclude instances based
on set logic.">can-connect/real-time/real-time</a> behavior automatically inserts newly created items into
lists that they belong within.</p>
<h2>List todos</h2>
<p>In this section, we will:</p>
<ul>
<li>Define a custom element that lists todos passed to it.</li>
<li>Use that custom element.</li>
</ul>
<p>Update the <code>JavaScript</code> tab to:</p>
<ul>
<li>Create a <code>TodoListVM</code> view model type which has a <code>todos</code> property of type <code>Todo.List</code>.</li>
<li>Use <a href="../can-component.html" title="Create a custom element that can be used to manage widgets or application logic.">can-component</a> to define a <code><todo-list></code> element.</li>
</ul>
<pre><code class="language-js">var todoAlgebra = new can.set.Algebra(
can.set.props.boolean("complete"),
can.set.props.id("id"),
can.set.props.sort("sort")
);
var todoStore = can.fixture.store([
{ name: "mow lawn", complete: false, id: 5 },
{ name: "dishes", complete: true, id: 6 },
{ name: "learn canjs", complete: false, id: 7 }
], todoAlgebra);
can.fixture("/api/todos", todoStore);
can.fixture.delay = 1000;
var Todo = can.DefineMap.extend({
id: "string",
name: "string",
complete: {type: "boolean", value: false}
});
Todo.List = can.DefineList.extend({
"#": Todo,
get active(){
return this.filter({complete: false});
},
get complete(){
return this.filter({complete: true});
}
});
can.connect.superMap({
url: "/api/todos",
Map: Todo,
List: Todo.List,
name: "todo",
algebra: todoAlgebra
});
var TodoCreateVM = can.DefineMap.extend({
todo: {Value: Todo},
createTodo: function(){
this.todo.save().then(function(){
this.todo = new Todo();
}.bind(this));
}
});
can.Component.extend({
tag: "todo-create",
view: can.stache.from("todo-create-template"),
ViewModel: TodoCreateVM
});
var TodoListVM = can.DefineMap.extend({
todos: Todo.List
});
can.Component.extend({
tag: "todo-list",
view: can.stache.from("todo-list-template"),
ViewModel: TodoListVM
});
var template = can.stache.from("todomvc-template");
var frag = template({todosPromise: Todo.getList({})});
document.body.appendChild(frag);
</code></pre>
<p><span line-highlight='56-64,only'></span>
Update the <code>HTML</code> tab to:</p>
<ul>
<li>Create the <code>todo-list-template</code> that loops through a list of <code>todos</code> (instead of <code>todosPromise.value</code>).</li>
<li>Create a <code><todo-list></code> element and set it's <code>todos</code> property to the resolved value of <code>todosPromise</code>
using <a href="../can-stache-bindings.toChild.html" title="One-way bind a value in the parent scope to the viewModel.">{to-child}</a>.</li>
</ul>
<pre><code class="language-html"><!DOCTYPE html>
<html>
<head>
<meta name="description" content="TodoMVC Guide 3.0 - List todos">
<meta charset="utf-8">
<meta name="viewport" content="width=device-width">
<title>JS Bin</title>
</head>
<body>
<script type='text/stache' id='todo-create-template'>
<input id="new-todo"
placeholder="What needs to be done?">
{($value)}="todo.name"
($enter)="createTodo()"/>
</script>
<script type='text/stache' id='todo-list-template'>
<ul id="todo-list">
{{#each todos}}
<li class="todo {{#if complete}}completed{{/if}}
{{#if isDestroying}}destroying{{/if}}">
<div class="view">
<input class="toggle" type="checkbox" {($checked)}="complete">
<label>{{name}}</label>
<button class="destroy" ($click)="destroy()"></button>
</div>
<input class="edit" type="text" value="{{name}}"/>
</li>
{{/each}}
</ul>
</script>
<script type="text/stache" id="todomvc-template">
<section id="todoapp">
<header id="header">
<h1>todos</h1>
<todo-create/>
</header>
<section id="main" class="">
<input id="toggle-all" type="checkbox">
<label for="toggle-all">Mark all as complete</label>
<todo-list {todos}="todosPromise.value"/>
</section>
<footer id="footer" class="">
<span id="todo-count">
<strong>{{todosPromise.value.active.length}}</strong> items left
</span>
<ul id="filters">
<li>
<a class="selected" href="#!"&g