Skip to content

Commit

Permalink
Merge pull request tastejs#52 from rniemeyer/knockout-updates
Browse files Browse the repository at this point in the history
KnockoutJS: add "Mark all as complete" checkbox and "Press Enter" tooltip.
  • Loading branch information
boushley committed Jan 6, 2012
2 parents 071564b + 78ed736 commit 2cb3d13
Show file tree
Hide file tree
Showing 2 changed files with 50 additions and 11 deletions.
6 changes: 5 additions & 1 deletion todo-example/knockoutjs/index.html
Expand Up @@ -12,9 +12,13 @@ <h1>Todos</h1>
<div class="content">
<div id="create-todo">
<input id="new-todo" data-bind="value: current, valueUpdate: 'afterkeydown', enterKey: add" placeholder="What needs to be done?" />
<span class="ui-tooltip-top" style="display: none;">Press Enter to save this task</span>
<span class="ui-tooltip-top" data-bind="visible: showTooltip" style="display: none;">Press Enter to save this task</span>
</div>
<div id="todos">
<div data-bind="visible: todos().length">
<input id="check-all" class="check" type="checkbox" data-bind="checked: allCompleted" />
<label for="check-all">Mark all as complete</label>
</div>
<ul id="todo-list" data-bind="foreach: todos">
<li data-bind="css: { editing: editing }">
<div class="todo" data-bind="css: { done : done }">
Expand Down
55 changes: 45 additions & 10 deletions todo-example/knockoutjs/js/todos.js
Expand Up @@ -40,51 +40,86 @@
var ViewModel = function(todos) {
var self = this;
//map array of passed in todos to an observableArray of Todo objects
this.todos = ko.observableArray(ko.utils.arrayMap(todos, function(todo) {
self.todos = ko.observableArray(ko.utils.arrayMap(todos, function(todo) {
return new Todo(todo.content, todo.done);
}));

//store the new todo value being entered
this.current = ko.observable();
self.current = ko.observable();

//add a new todo, when enter key is pressed
this.add = function (data, event) {
self.add = function (data, event) {
var newTodo = new Todo(self.current());
self.todos.push(newTodo);
self.current("");
};

//remove a single todo
this.remove = function (todo) {
self.remove = function (todo) {
self.todos.remove(todo);
};

//remove all completed todos
this.removeCompleted = function () {
self.removeCompleted = function () {
self.todos.remove(function(todo) {
return todo.done();
});
};

//count of all completed todos
this.completedCount = ko.computed(function () {
self.completedCount = ko.computed(function () {
return ko.utils.arrayFilter(self.todos(), function(todo) {
return todo.done();
}).length;
});

//count of todos that are not complete
this.remainingCount = ko.computed(function () {
self.remainingCount = ko.computed(function () {
return self.todos().length - self.completedCount();
});

//writeable computed observable to handle marking all complete/incomplete
self.allCompleted = ko.computed({
//always return true/false based on the done flag of all todos
read: function() {
return !self.remainingCount();
},
//set all todos to the written value (true/false)
write: function(newValue) {
ko.utils.arrayForEach(self.todos(), function(todo) {
//set even if value is the same, as subscribers are not notified in that case
todo.done(newValue);
});
}
});

//track whether the tooltip should be shown
self.showTooltip = ko.observable(false);
self.showTooltip.setTrue = function() { self.showTooltip(true); }; //avoid an anonymous function each time

//watch the current value
self.current.subscribe(function(newValue) {
//if the value was just updated, then the tooltip should not be shown
self.showTooltip(false);

//clear the current timer, as it is actively being updated
if (self.showTooltip.timer) {
clearTimeout(self.showTooltip.timer);
}

//if there is a value and then show the tooltip after 1 second
if (newValue) {
self.showTooltip.timer = setTimeout(self.showTooltip.setTrue, 1000);
}
});

//helper function to keep expressions out of markup
this.getLabel = function(count) {
self.getLabel = function(count) {
return ko.utils.unwrapObservable(count) === 1 ? "item" : "items";
};

//computed observable that fires whenever anything changes in our todos
this.isDirty = ko.computed(function() {
//internal computed observable that fires whenever anything changes in our todos
ko.computed(function() {
//get a clean copy of the todos, which also creates a dependency on the observableArray and all observables in each item
var todos = ko.toJS(self.todos);

Expand Down

0 comments on commit 2cb3d13

Please sign in to comment.