Skip to content

Instantly share code, notes, and snippets.

@linuxenko
Created March 25, 2016 21:19
Show Gist options
  • Save linuxenko/b8bcfb5af070ad4fe96a to your computer and use it in GitHub Desktop.
Save linuxenko/b8bcfb5af070ad4fe96a to your computer and use it in GitHub Desktop.
Angular 1.x TodoList
<body ng-app="todoApp" ng-controller="todoCtrl">
<section class="todoapp">
<header class="header">
<h1>Angular 1.x</h1>
<input ng-keypress="createTodo($event, newTodoTitle)" ng-model="newTodoTitle" class="new-todo" placeholder="What needs to be done?" autofocus>
</header>
<section class="main">
<input class="toggle-all" type="checkbox" ng-click="toggleAll($event)">
<label for="toggle-all">Mark all as complete</label>
<ul class="todo-list">
<li todo-item ng-repeat='todo in todos' ng-class="{completed : todo.completed}">
<div class="view" ng-if="status === null || status === 'active' && todo.completed === false || status === 'completed' && todo.completed === true">
<input ng-click="toggle(todo.id)" class="toggle" type="checkbox" ng-checked="todo.completed">
<label>{{todo.title}}</label>
<button ng-click="remove(todo.id)" class="destroy"></button>
</div>
<input ng-keydown="save($event, todo.id, saveTodoVal)"
ng-model="saveTodoVal" ng-init="saveTodoVal=todo.title" class="edit">
</li>
</ul>
</section>
<footer class="footer">
<span class="todo-count">
<strong total-todos>0</strong> item left</span>
<ul class="filters">
<li>
<a ng-class="{selected: status === null}" href="#/">All</a>
</li>
<li>
<a ng-class="{selected: status === 'active'}" href="#/active">Active</a>
</li>
<li>
<a ng-class="{selected: status === 'completed'}" href="#/completed">Completed</a>
</li>
</ul>
<button ng-click="clearCompleted()" class="clear-completed">Clear completed</button>
</footer>
</section>
<footer class="info">
<p>Double-click to edit a todo</p>
</footer>
</body>
var app = angular.module('todoApp', ['ngRoute'])
.config(function ($routeProvider) {
$routeProvider.when('/:status', {
controller : 'todoCtrl'
});
});
app.factory('todo', function() {
function guid() {
function s4() {
return Math.floor((1 + Math.random()) * 0x10000)
.toString(16)
.substring(1);
}
return s4() + s4() + '-' + s4() + '-' + s4() + '-' +
s4() + '-' + s4() + s4() + s4();
}
return {
todos : [],
add : function(title, completed) {
this.todos.push({id : guid(),
title : title, completed : completed || false});
},
save : function(id, title) {
for (var i = 0; i < this.todos.length; i++) {
if (this.todos[i].id === id) {
this.todos[i].title = title;
}
}
},
remove : function(id) {
for (var i = 0; i < this.todos.length; i++) {
if (this.todos[i].id === id) {
this.todos.splice(i, 1);
}
}
},
toggle : function(id, status) {
for (var i = 0; i < this.todos.length; i++) {
if (this.todos[i].id === id) {
this.todos[i].completed = status ? status : !this.todos[i].completed;
}
}
}
}
});
app.directive('todoItem', function() {
return {
restrict : 'A',
link : function(scope, e, attr) {
function removeEditing() {
[].slice.call(document.querySelectorAll('.editing'))
.forEach(function(el) {
el.classList.remove('editing');
});
}
e.on('keydown', function(ev) {
if (ev.code === 'Enter') {
removeEditing();
}
});
e.on('click', function(ev) {
if (ev.target.tagName === 'INPUT') { return ;}
removeEditing();
});
e.on('dblclick', function(ev) {
ev.target.parentNode.parentNode.classList.add('editing');
});
}
}
});
app.directive('totalTodos', function() {
return {
restrict : 'A',
link : function(scope, e) {
scope.$watch('todos', function() {
var total = scope.todos.filter(function(t) {
return t.completed === false;
}).length;
scope.totals = total;
}, true);
},
template : '{{totals}}'
}
});
app.controller('todoCtrl', function($scope, $routeParams, todo) {
$scope.status = null;
$scope.$on('$routeChangeSuccess', function(e,p) {
$scope.status = p ? p.params.status : null;
});
$scope.todos = todo.todos;
$scope.toggle = function(id) { todo.toggle(id); }
$scope.save = function(ev, id, title) {
if (ev.code === 'Enter' && title.length > 0) {
todo.save(id, title);
}
}
$scope.remove = function(id) { todo.remove(id); }
$scope.createTodo = function(ev, title) {
if (ev.code === 'Enter' && title.length > 0) {
todo.add(title, false);
ev.target.value = '';
}
}
$scope.toggleAll = function(ev) {
var state = ev.target.checked;
$scope.todos.forEach(function(t) {
todo.toggle(t.id, state);
});
}
$scope.clearCompleted = function() {
var toremove = [];
$scope.todos.forEach(function(t) {
if (t.completed === true) {
toremove.push(t.id);
}
});
toremove.forEach(function(id) { todo.remove(id); } );
}
todo.add('Publish and forget', false);
todo.add('Make filtering support', true);
todo.add('Display todos list', true);
todo.add('Create todo boilerplate', true);
});
<script src="//cdnjs.cloudflare.com/ajax/libs/angular.js/1.5.2/angular.min.js"></script>
<script src="https://cdnjs.cloudflare.com/ajax/libs/angular.js/1.5.2/angular-route.js"></script>
<link href="https://cdn.rawgit.com/tastejs/todomvc-app-css/master/index.css" rel="stylesheet" />
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment