Smalltalk current createPackage: 'Trapped-Demo' properties: #{}! ListKeyedIsolatedEntity subclass: #App instanceVariableNames: '' package: 'Trapped-Demo'! !App commentStamp! // Code from AngularJS Todo example, http://angularjs.org/#todo-js function TodoCtrl($scope) { $scope.todos = [ {text:'learn angular', done:true}, {text:'build an angular app', done:false}]; $scope.addTodo = function() { $scope.todos.push({text:$scope.todoText, done:false}); $scope.todoText = ''; }; $scope.remaining = function() { var count = 0; angular.forEach($scope.todos, function(todo) { count += todo.done ? 0 : 1; }); return count; }; $scope.archive = function() { var oldTodos = $scope.todos; $scope.todos = []; angular.forEach(oldTodos, function(todo) { if (!!todo.done) $scope.todos.push(todo); }); }; }! !App methodsFor: 'initialization'! initialize super initialize. self dispatcher: SimpleKeyedPubSub new. self model: (AppModel new title: 'Todo'). [ self modify: #(#todos) do: [{ #{'text'->'learn trapped'. 'done'->true}. #{'text'->'build a trapped app'. 'done'->false} }]] valueWithTimeout: 2000 ! ! Object subclass: #AppModel instanceVariableNames: 'title todos todoText' package: 'Trapped-Demo'! !AppModel commentStamp! // Code from AngularJS Todo example, http://angularjs.org/#todo-js function TodoCtrl($scope) { $scope.todos = [ {text:'learn angular', done:true}, {text:'build an angular app', done:false}]; $scope.addTodo = function() { $scope.todos.push({text:$scope.todoText, done:false}); $scope.todoText = ''; }; $scope.remaining = function() { var count = 0; angular.forEach($scope.todos, function(todo) { count += todo.done ? 0 : 1; }); return count; }; $scope.archive = function() { var oldTodos = $scope.todos; $scope.todos = []; angular.forEach(oldTodos, function(todo) { if (!!todo.done) $scope.todos.push(todo); }); }; }! !AppModel methodsFor: 'accessing'! remaining ^self todosNotDone size ! title ^title ! title: aString title := aString ! todoText ^todoText ! todoText: aString todoText := aString ! todos ^todos ! todos: anArray todos := anArray ! todosNotDone ^self todos reject: [ :each | each at: 'done' ] ! ! !AppModel methodsFor: 'action'! addTodo self todos add: #{'text'->self todoText. 'done'->false}. self todoText: '' ! archive self todos: self todosNotDone ! ! Widget subclass: #AppView instanceVariableNames: '' package: 'Trapped-Demo'! !AppView commentStamp!

Todo

{{remaining()}} of {{todos.length}} remaining [ archive ]
! !AppView methodsFor: 'rendering'! renderOn: html #() trapDescend: [ :snap | html h2 trap: #(#title). html div trap: #(#todos) toggle: [ snap do: [ html span trap:#(#remaining). html with: ' of '. html span trap: #(#todos #size). html with: ' remaining [ '. html a href:''; onClick: [[ snap modify: [ :model | model archive ]. false ] value "amber GH-314 workaround"]; with: 'archive'. html with: ' ]'. html ul trapIter: #(#todos) tag: #li do: [ :each | html root empty. html input type: 'checkbox'; trap: #('done'). html span trap: #('done') read: [ :model | html root class: 'done-', model ]; trap: #('text'). ]. html form onSubmit: [[ snap modify: [ :model | model addTodo ]. false ] value "amber GH-314 workaround"]; with: [ html input type: 'text'; trap: #(#todoText); at: 'size' put: 30; placeholder: 'add new todo here'. html input class: 'btn-primary'; type: 'submit'; value: 'add'. ]. ]] ifNotPresent: [ html with: 'Loading ...' ]] ! !