Created
April 3, 2015 16:33
-
-
Save leehsueh/5e68b416549669dfbcbf to your computer and use it in GitHub Desktop.
Basic Flux Todo with Vanilla Angular
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
angular.module('fluxTodo') | |
.directive('todoApp', function() { | |
return { | |
restrict: 'EA', | |
template: '<h1>Flux To Do List <button ng-click="loadSeedTodos()">Load Sample</button></h1>' + | |
'<summary></summary>' + | |
'<new-todo></new-todo>' + | |
'<task-list></task-list>' | |
} | |
}) | |
.directive('summary', function() { | |
return { | |
restrict: 'E', | |
template: '{{doneCount}} completed, {{undoneCount}} items left', | |
scope: { | |
change: '=' | |
}, | |
controller: function($scope, TodoStore) { | |
$scope.undoneCount = 0; | |
$scope.doneCount = 0; | |
var onChange = function() { | |
$scope.undoneCount = TodoStore.getUndoneCount(); | |
$scope.doneCount = TodoStore.getDoneCount(); | |
}; | |
TodoStore.addChangeListener(onChange, 'summary'); | |
} | |
}; | |
}) | |
.directive('taskList', function() { | |
return { | |
restrict: 'E', | |
controller: function($scope, TodoStore) { | |
var onChange = function() { | |
// get the updated list of tasks from the store | |
var tasks = TodoStore.getAll(); | |
console.log(tasks); | |
var list = []; | |
for (var key in tasks) { | |
list.push(tasks[key]); | |
} | |
console.log('Handling Change') | |
console.log(list) | |
$scope.tasks = list; | |
}; | |
// register change listener | |
TodoStore.addChangeListener(onChange, 'taskList'); | |
}, | |
template: '<ul>' + | |
'<li ng-repeat="t in tasks"><todo-item todo="t"></li></ul>' | |
}; | |
}) | |
.directive('todoItem', function() { | |
return { | |
restrict: 'EA', | |
scope: { | |
todo: '=', | |
}, | |
controller: function($scope, TodoActionCreator) { | |
$scope.toggleTodo = function(id) { | |
TodoActionCreator.toggleTodo(id); | |
}; | |
}, | |
template: '<input type="checkbox" ng-checked="todo.completed" ng-click="toggleTodo(todo.id)"> {{todo.text}}' | |
}; | |
}) | |
.directive('newTodo', function() { | |
return { | |
restrict: 'EA', | |
template: '<input type="text" ng-model="newTodo"> <button ng-click="addTodo(newTodo); newTodo = null">Add</button>', | |
controller: function($scope, TodoActionCreator) { | |
$scope.addTodo = function(text) { | |
console.log(text); | |
TodoActionCreator.createTodo(text); | |
}; | |
} | |
}; | |
}) |
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
// naive Dispatcher implementation | |
// based on https://facebook.github.io/flux/docs/todo-list.html#content | |
angular.module('fluxTodo').factory('dispatcher', function() { | |
var _callbacks = []; | |
var _promises = []; | |
return { | |
register: function(callback) { | |
console.log('Registering'); | |
_callbacks.push(callback); | |
return _callbacks.length -1 ; | |
}, | |
dispatch: function(payload) { | |
console.log('Dispatching: ' + payload.action.actionType); | |
var resolves = []; | |
var rejects = []; | |
_promises = _callbacks.map(function(_, i) { | |
return new Promise(function(resolve, reject) { | |
resolves[i] = resolve; | |
rejects[i] = reject; | |
}); | |
}); | |
// dispatch to callbacks and reoslve/reject promises | |
console.log(_callbacks.length); | |
_callbacks.forEach(function(callback, i) { | |
Promise.resolve(callback(payload)).then(function() { | |
resolves[i](payload); | |
}, function() { | |
rejects[i](new Error('Dispatcher callback unsuccessful')); | |
}); | |
}); | |
_promises = []; | |
}, | |
handleViewAction: function(action) { | |
this.dispatch({ | |
source: 'VIEW_ACTION', | |
action: action | |
}); | |
} | |
}; | |
}); |
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
<!DOCTYPE html> | |
<html> | |
<head> | |
<script data-require="[email protected]" data-semver="1.2.28" src="https://code.angularjs.org/1.2.28/angular.js"></script> | |
<link rel="stylesheet" href="style.css" /> | |
<script src="script.js"></script> | |
<script src="dispatcher.js"></script> | |
<script src="TodoStore.js"></script> | |
<script src="TodoActionCreator.js"></script> | |
<script src="directives.js"></script> | |
<script src="TodoCtrl.js"></script> | |
</head> | |
<body ng-app="fluxTodo"> | |
<todo-app ng-controller="TodoCtrl"></todo-app> | |
</body> | |
</html> |
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
angular.module('fluxTodo').factory('TodoActionCreator', function(dispatcher) { | |
return { | |
createTodo: function(text) { | |
dispatcher.handleViewAction({ | |
actionType: 'CREATE', | |
text: text | |
}); | |
}, | |
toggleTodo: function(id) { | |
dispatcher.handleViewAction({ | |
actionType: 'TOGGLE', | |
id: id | |
}); | |
}, | |
loadSeedTodos: function() { | |
dispatcher.handleViewAction({ | |
actionType: 'SEED', | |
seedTodos: { | |
1423265707942: { | |
id: 1423265707942, | |
text: 'Read about Flux architecture', | |
completed: false | |
}, | |
1423265707980: { | |
id: 1423265707980, | |
text: 'Study examples', | |
completed: false | |
}, | |
1423265708000: { | |
id: 1423265708000, | |
text: 'Build something', | |
completed: false | |
}, | |
} | |
}); | |
} | |
}; | |
}) |
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
angular.module('fluxTodo') | |
.controller('TodoCtrl', function($scope, TodoStore, TodoActionCreator) { | |
// $scope.todoStoreChange = TodoStore.emitChange; | |
// Seed | |
$scope.loadSeedTodos = function() { | |
TodoActionCreator.loadSeedTodos(); | |
}; | |
}) |
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
angular.module('fluxTodo').factory('TodoStore', function(dispatcher) { | |
// Event emitting and listening boilerplate | |
var _changeCallbacks = []; | |
var _todos = {}; | |
function create(text) { | |
console.log('Creating todo: ' + text); | |
var id = Date.now(); | |
_todos[id] = { | |
id: id, | |
complete: false, | |
text: text | |
}; | |
} | |
function destroy(id) { | |
delete _todos[id]; | |
} | |
var TodoStore = { | |
getAll: function() { return _todos; }, | |
getUndoneCount: function() { | |
var count = 0; | |
for (var key in _todos) { | |
if (!_todos[key].completed) { | |
count++; | |
} | |
} | |
return count; | |
}, | |
getDoneCount: function() { | |
return Object.keys(_todos).length - this.getUndoneCount(); | |
}, | |
emitChange: function(type) { | |
console.log('Broadcasting change from ' + type); | |
_changeCallbacks.forEach(function(callback) { | |
callback(); | |
}) | |
}, | |
addChangeListener: function(callback, source) { | |
console.log('Adding change listener from ' + source); | |
_changeCallbacks.push(callback); | |
}, | |
dispatcherIndex: dispatcher.register(function(payload) { | |
var action = payload.action; | |
var text; | |
console.log('Handling event: ' + action.actionType); | |
switch(action.actionType) { | |
case 'SEED': | |
_todos = action.seedTodos; | |
TodoStore.emitChange(action.actionType); | |
break; | |
case 'CREATE': | |
text = action.text.trim(); | |
if (text !== '') { | |
create(text); | |
TodoStore.emitChange(action.actionType); | |
} | |
break; | |
case 'TOGGLE': | |
_todos[action.id].completed = !_todos[action.id].completed; | |
TodoStore.emitChange(action.actionType); | |
break; | |
case 'DESTROY': | |
destroy(action.id); | |
TodoStore.emitChange(); | |
break; | |
} | |
return true; | |
}) | |
}; | |
return TodoStore; | |
}) |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment