Skip to content

Instantly share code, notes, and snippets.

@youknowriad youknowriad/application.js Secret
Created Nov 16, 2015

Embed
What would you like to do?
Angular.js Simple Todo, Store, Redux
angular.module('todoApp', []);
<!doctype html>
<html ng-app="todoApp">
<head>
<script src="https://cdnjs.cloudflare.com/ajax/libs/EventEmitter/4.3.0/EventEmitter.min.js"></script>
<script src="https://ajax.googleapis.com/ajax/libs/angularjs/1.4.7/angular.min.js"></script>
<script src="https://cdnjs.cloudflare.com/ajax/libs/redux/3.0.4/redux.min.js"></script>
<script src="application.js"></script>
<script src="store.js"></script>
<script src="service.js"></script>
<script src="todo-actions.js"></script>
<script src="todos.js"></script>
<script src="todo-remaining.js"></script>
<script src="todo-create.js"></script>
</head>
<body>
<h2>Todo</h2>
<todo-remaining></todo-remaining>
<todos></todos>
<todo-create></todo-create>
</body>
</html>
function todoRepository(todoStore, $q) {
this.$q = $q;
this.store = todoStore;
this.todos = [
{id: 1, text:'learn angular', done:true},
{id: 2, text:'build an angular app', done:false}
];
this.nextId = 3;
}
todoRepository.prototype.findAll = function() {
return this.$q.when(angular.copy(this.todos));
}
todoRepository.prototype.update = function(todo) {
var index = this.todos.findIndex(function(elt) { return elt.id === todo.id });
if (index !== -1) {
this.todos[index] = todo;
}
return this.$q.when(angular.copy(todo));
}
todoRepository.prototype.create = function(todo) {
var newTodo = angular.copy(todo);
newTodo.id = this.nextId;
this.nextId++;
this.todos.push(newTodo);
return this.$q.when(newTodo);
}
todoRepository.prototype.archive = function() {
this.todos = this.todos.filter(function(todo) {
return !todo.done;
});
return this.$q.when(angular.copy(this.todos));
}
angular.module('todoApp').service('todoRepository', todoRepository);
function todoReducer(state, action) {
switch (action.type) {
case 'add-todo':
var newState = state.slice();
newState.push(angular.copy(action.todo));
return newState;
case 'update-todo':
return state.map(function(todo) {
if (todo.id === action.todo.id) {
return angular.copy(action.todo);
} else {
return todo;
}
});
case 'load-todos':
return action.todos.slice();
default:
return state;
}
}
function promiseMiddleware(store) {
return function(next) {
return function(action) {
return action && typeof action.then === 'function'
? action.then(result => store.dispatch(result))
: next(action);
}
}
}
angular.module('todoApp').factory('todoStore', function() {
var createStoreWithMiddleware = Redux.applyMiddleware(promiseMiddleware)(Redux.createStore);
return createStoreWithMiddleware(todoReducer, []);
});
function TodoActions(todoRepository) {
this.repository = todoRepository;
}
TodoActions.prototype.addTodo = function(todo) {
return this.repository.create(todo).then(function(createdTodo) {
return {
type: 'add-todo',
todo: createdTodo
};
});
}
TodoActions.prototype.updateTodo = function(todo) {
return this.repository.update(todo).then(function(updatedTodo) {
return {
type: 'update-todo',
todo: updatedTodo
};
});
}
TodoActions.prototype.loadTodos = function() {
return this.repository.findAll().then(function(todos) {
return {
type: 'load-todos',
todos: todos
};
});
}
TodoActions.prototype.archiveTodos = function() {
return this.repository.archive().then(function(todos) {
return {
type: 'load-todos',
todos: todos
};
});
}
angular.module('todoApp').service('todoActions', TodoActions);
angular.module('todoApp').directive('todoCreate', function() {
return {
restrict: 'E',
scope: true,
controller: function($scope, todoStore, todoActions) {
$scope.newTodo = {};
$scope.addTodo = function() {
todoStore.dispatch(todoActions.addTodo($scope.newTodo)).then(function() {
$scope.newTodo = {};
});
};
},
template: `
<form ng-submit="addTodo()">
<input type="text" ng-model="newTodo.text" size="30"
placeholder="add new todo here">
<input class="btn-primary" type="submit" value="add">
</form>
`
}
});
angular.module('todoApp').directive('todoRemaining', function() {
return {
restrict: 'E',
scope: true,
controller: function($scope, todoStore, todoActions) {
todoStore.dispatch(todoActions.loadTodos());
$scope.todos = todoStore.getState();
todoStore.subscribe(function(todos) {
$scope.todos = todoStore.getState();
});
$scope.remaining = function() {
var count = 0;
angular.forEach($scope.todos, function(todo) {
count += todo.done ? 0 : 1;
});
return count;
};
$scope.archive = function() {
todoStore.dispatch(todoActions.archiveTodos());
};
},
template: `
<span>{{remaining()}} of {{todos.length}} remaining</span>
[ <a href="" ng-click="archive()">archive</a> ]
`
}
});
angular.module('todoApp').directive('todos', function() {
return {
restrict: 'E',
scope: true,
controller: function($scope, todoStore, todoActions) {
todoStore.dispatch(todoActions.loadTodos());
$scope.todos = todoStore.getState();
todoStore.subscribe(function(todos) {
$scope.todos = todoStore.getState();
});
$scope.update = function(todo) {
todoActions.updateTodo(todo);
}
},
template: `
<ul class="unstyled">
<li ng-repeat="todo in todos">
<input type="checkbox" ng-model="todo.done" ng-change="update(todo)">
<span class="done-{{todo.done}}">{{todo.text}}</span>
</li>
</ul>
`
}
});
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
You can’t perform that action at this time.
You signed in with another tab or window. Reload to refresh your session. You signed out in another tab or window. Reload to refresh your session.