How to Write a Sophisticated SPA: TodoMVC using C#

Muigai Mwaura
HackerNoon.com
6 min readApr 28, 2017

--

If you’ve been looking to use C# to develop Single Page Applications which would otherwise require the use of JavaScript paired with a framework like Angular or React. Read on…

In this article we’ll be making use of Bridge.Net (a C# to JavaScript transpiler) and SharpBindings (a DSL for creating HTML elements via the DOM) to implement the well-known TodoMVC application in pure C# code.

[Live Demo]

In the process we will demonstrate how to leverage C# features that you know and love such as generics, LINQ, lambdas etc. to build out sophisticated SPA functionality.

Getting Started

We shall begin by translating the header section defined as follows in html,

into C# using SharpBindings as follows:

As you can see there is a one-to-one correspondence between the HTML tags and attributes, and the C# code with respect to static content. The dynamic behavior of the application however requires that:

New todos are entered in the input at the top of the app… Pressing Enter creates the todo, appends it to the todo list, and clears the input. Make sure to .trim() the input and then check that it’s not empty before creating a new todo.

To enable this we need support for functions, event handlers and data binding as per the full code listing below:

The Todo class referenced above is a standard C# class with two properties, a description of the todo and an “IsCompleted” flag indicating whether it is done or not. In addition it supports the standard INotifyPropertyChanged interface.

The ObservableCollection is a class that holds a list of elements and emits change notifications whenever an element:

  1. Has it’s position changed within the list
  2. Is added to the list
  3. Is removed from the list

The following non-obvious points should be noted:

  1. We bind the “value” attribute of the input element to a function, since the description of the editing todo changes in response to user interaction and programmatic events, and will need to be re-evaluated accordingly.
  2. We introduce a “watch” attribute that is bound to the editing todo. Any time the the editing todo changes we reevaluate data-bindings for the input element, and change only those aspects of the DOM that need to be updated.

The combination of the two above ensure that the input is cleared after this line of code runs

Next up is the footer section which is defined as follows in html,

the translation to C# using SharpBindings follows:

There is still a strong resemblance between the HTML tags and attributes, and the C# code but this time the dynamic behavior is much more extensive than in the header section. As per the spec:

“When there are no todos the … #footer should be hidden.”

“Display… the number of active todos in a pluralized form. Make sure the number is wrapped by a <strong> tag. Also make sure to pluralize the item word correctly: 0 items, 1 item, 2 items. Example: 2 items left.”

“Clear completed button… Removes completed todos when clicked. Should be hidden when there are no completed todos.”

“Routing is required… The following routes should be implemented: #/ (all — default), #/active and #/completed… When the route changes, the todo list should be filtered on a model level and the selected class on the filter links should be toggled. When an item is updated while in a filtered state, it should be updated accordingly. E.g. if the filter is Active and the item is checked, it should be hidden. Make sure the active filter is persisted on reload.”

These requirements are implemented as per the full code listing below:

The FooterSection function above takes four arguments:

  1. An ObservableCollection of todos (same as the header section)
  2. A function that returns the number of todos that are active
  3. The filters (all, active and completed) as described in the spec
  4. An observable called “urlTrigger” that will emit a change notification any time the url changes

The following non-obvious point should be noted:

1) Rather than writing out each filter URL as in the HTML template:

We specify the filters as a collection of items, each of which is to be rendered using the supplied template:

Finally we have the main section which is defined as follows in html:

The translation to C# using SharpBindings follows:

We then need to implement the following dynamic behavior as per the spec:

“When there are no todos, #main… should be hidden.”

“Mark all as complete… checkbox toggles all the todos to the same state as itself. Make sure to clear the checked state after the ‘Clear completed’ button is clicked. The ‘Mark all as complete’ checkbox should also be updated when single todo items are checked/unchecked. Eg. When all the todos are checked it should also get checked.”

These requirements are implemented as per the full code listing below:

The MainSection function above takes three arguments:

  1. An ObservableCollection of todos (same as the header section)
  2. A function that returns the number of todos that are active
  3. A template function that takes a todo item and returns a rendered HTML element as explained below.

The Todo item template is defined as follows in html:

The translation to C# using SharpBindings follows:

We then need to implement the following dynamic behavior as per the spec:

“Item

A todo item has three possible interactions:

Clicking the checkbox marks the todo as complete by updating its completed value and toggling the class completed on its parent <li>

Double-clicking the <label> activates editing mode, by toggling the .editing class on its <li>

Hovering over the todo shows the remove button (.destroy)

Editing

When editing mode is activated it will hide the other controls and bring forward an input that contains the todo title, which should be focused (.focus()). The edit should be saved on both blur and enter, and the editing class should be removed. Make sure to .trim() the input and then check that it’s not empty. If it’s empty the todo should instead be destroyed. If escape is pressed during the edit, the edit state should be left and any changes be discarded.”

That’s quite a mouthful and requires a non-trivial amount of code to implement as below:

The TodoTemplate function above takes three arguments:

  1. An Action to remove a todo from the list of todos
  2. An observable called “urlTrigger” (same as the footer)
  3. A currentFilter which will keep track of the user selected filter as described in the footer. The currentFilter will determine which todo items to show based on the filter condition.

The following non-obvious point should be noted

  • The class of each rendered todo item (hidden, completed, editing or none of the above), depends on
    a) The state of the item (active or completed)
    b) The selected filter
    c) Whether it is in edit mode
    We therefore need to merge change notification signals from three sources as below:
  • The initiation of editing mode is as follows:
    a) The user double clicks on the label/description of the to-do item
    b) The label responds by setting “isEditMode” to true
    c) This triggers the display of the textbox for editing

To bring it all together we have a “Main” function (the entry point to the application) defined as below:

And there you have it, a reasonably concise, literal translation of the specs for TodoMVC to C# via Bridge.NET and SharpBindings.

Notes:

  1. Implementation of persistence is not yet supported, as serialization of C# classes to JSON appears to be a work in progress in Bridge.NET. Will implement that and update the article as soon as support for JSON serialization is available.
  2. The project sources can be obtained from Github here.
  3. The Scala implementation of TodoMVC from which this drew inspiration.

Hacker Noon is how hackers start their afternoons. We’re a part of the @AMIfamily. We are now accepting submissions and happy to discuss advertising & sponsorship opportunities.

To learn more, read our about page, like/message us on Facebook, or simply, tweet/DM @HackerNoon.

If you enjoyed this story, we recommend reading our latest tech stories and trending tech stories. Until next time, don’t take the realities of the world for granted!

--

--