TodoList Example

This example is built in three layers: the model, the user interface, and the data.

file: example/todo/model/
class TodoList {
   class TodoItem {
      String text;
      boolean complete;

      TodoItem(String t, boolean c) {
          text = t;
          complete = c;
   ArrayList<TodoItem> todos; /* = {
      new TodoItem("Run layerCake todo sample", true),
      new TodoItem("Check me and see it stay in sync", false),
      new TodoItem("Add a new entry and press 'remove completed'", false),
   } */;

   String todoText = "";

   void addTodoEntry() {
      todos.add(new TodoItem(todoText, false));
      todoText = "";

   int getRemaining(List<TodoItem> todoList) {
      int count = 0;
      if (todoList == null) {
         System.out.println("*** no list");
         return 0;
      for (TodoItem todo: todoList) {
         if (!todo.complete)
      return count;

   int getSize(List<TodoItem> list) {
      return list == null ? 0 : list.size();

   void removeComplete() {
      for (int i = 0; i < todos.size(); i++) {
         TodoItem todo = todos.get(i);
         if (todo.complete) {

Here is the user interface, in the example.todo.jsui layer. That layer extends the model layer so this file modifies the Todo type above. That happens because these files have the same name and the layers use the same package. You have access to the properties in the model layer, just like the "code behind" pattern.
file: example/todo/jsui/TodoList.schtml
<!-- TodoList.schtml modifies the TodoList class in the previous model layer.
     Setting 'needsRefresh' here because the 'getRemaining' method needs to be
     refreshed after any changes to the page are made. -->
<html needsRefresh="true">
      <link rel="stylesheet" type="text/css" href="todoStyle.css" />
     <div class="appFrame">
        <h2>Todo List</h2>
        <div id="todoControl">
           <!-- These next two expressions are updated incrementally in response to property change events.  For 'getSize' we detect
                change events when the 'todos' list changes because it uses sc.util.ArrayList.  It's trickier with getRemaining 
                because it also needs to run after any change to a TodoItem's 'complete' value.  To handle that, rather than trigger
                an extra event during that event, we take the easy way out and set needsRefresh on the page.  In that mode, after
                any input events are fired, we revalidate all bindings in a 'do later' operation. -->
           <span><%= getRemaining(todos) %> of <%= getSize(todos) %> to do</span>
           <!-- The clickEvent property is updated when the anchor tag is clicked on.  When that happens the binding calls: 'removeComplete()' -->
           [ <a href="#" clickEvent="=: removeComplete()">remove completed</a> ]
              <!-- Repeat the li tag once for each element in the todos list.
                As the list changes, tags are added/removed as needed -->
              <li repeat=":= todos" repeatVarName="todo">
                 <!-- Set checked to the value of todo.complete and vice-versa -->
                 <input type="checkbox" checked=":=: todo.complete"/>
                 <!-- Add a class to this span tag when it is done -->
                 <span class='<%= "complete-" + todo.complete %>'><%= todo.text%></span>
           <form submitEvent="=: addTodoEntry()">
              <input type="text" value=":=: todoText" size="45" placeholder="enter todo entry here"/>
              <input type="submit" value="Add" disabled=':= TextUtil.length(todoText) == 0'/>
and a separate layer to store the data:
file: example/todo/data/
// Specifies the data to initialize the todo list.  
TodoList {
   todos = {
      new TodoItem("Run StrataCode todo sample", true),
      new TodoItem("Check me and see it stay in sync", false),
      new TodoItem("Add a new entry and press 'remove completed'", false)
We can run this layer in two different modes. If we compile it with just the js.schtml layer, it runs in the browser only (as you see above). If we compile it with both the js.schtml and jetty.schtml layers, it runs in a synchronized way. As each model entry is changed, its value is sent to the server and saved. This configuration is configured to just save the data in the user's session.