Valaa Tutorial: Simple To-Do

Collaborative task manager with 63 lines of code.

Ville Topias Ilkkala
valaa.log
8 min readJan 24, 2018

--

The result of this tutorial, displaying two users at the same time.

This is the second Valaa tutorial post in. I go quite a bit faster in this, so I recommend checking out the first Hello, World! tutorial before continuing.

Valaa is designed to make the development of real-time and multi-user applications as smooth as possible. In this tutorial we will create a simple to-do application that supports multiple users and allows them to share tasks with each other.

Application Structure

We again start by using the Valaa IDE to visually map out our project structure.

Project root

In our project root we create two Entities: client and tasks. We will later instance the client to the user’s local partition to achieve independent UI state. For that we also need two more Medias: partition.vsx with a LENS property pointing to it and a createLocalPartition.vs with an accessor property.

Client

The client Entity should have two properties, user set to null for the username and hideCompleted set to false. Here we need to add two more Medias: For the user interface we create ui.vsx with a LENS property pointing to it. For styles we create styles.css with an accessor property. A property tasks should be created and set to point to the tasks Entity in our project root.

Tasks

Tasks will take advantage of Valaa’s powerful instancing mechanism. We will also use Relations to store our tasks, but won’t assign targets for them. This is occasionally faster and simpler than creating separate Entities to store data and then referencing them with Relations.

We start by creating a Relation called Task with an accessor property as the prototype for actual tasks and assign following properties to it:

  • user set to null
  • isPrivate set to true
  • text set to null
  • done set to false
  • date set to null

Finally, we need a piece of ValaaScript for creating new instances of the Task Relation. For that we create a new Media called newTask.vs and add an accessor property for it.

Finished data structure for our application. Gray is for Entities, blue for Properties, yellow for Relations and pink for Medias.

Local Instancing

In the previous tutorial all users shared the same UI state. This is not an issue for personal applications or when the shared UI is intended behavior. For most multi-user applications additional effort is needed to allow users to interact with the application without interfering with other users.

Local instancing is an easy method for achieving independent UI state for different users. Local instances are instances of Valaa Entities that are stored in the browser using the IndexedDB API instead of the Valaa cloud. They still reflect prototype modifications from the cloud, so users don’t have to clear their browser’s cache to see updates to our app.

For this we use Valaa’s custom <ValaaScope> element. It renders an Entity passed to it through the focus property. You can specify what Lens to use from that Entity with the lensName. The focus can also be returned from a function— a local instance of our client Entity in this case. Let’s write the following to our partition.vsx in the project root:

The function below is the createLocalPartition.vs used above and located in the project root. It will first check if the user already has a local instance and if yes, will return it. This prevents the UI state from being lost between sessions. If this is the first time vising the app, the function will create a new local instance and return that instead.

ValaaScript function for creating the local partition. It will be merged to the standard library in the near future.

I will not go through the function in more detail, as we will include a utility function for this task in Valaa’s standard library in the near future.

Creating New Tasks

Our users want to create new tasks. For that we are going to instance the Task Relation we created earlier. The newTask.vs inside tasks Entity should look like this:

Please note, that the file extension in Gist is incorrectly .js to get automated syntax highlighting from syntactically identical JavaScript. For VS files the correct file extension is .vs.

Let’s look the function line by line:

Our function takes two parameters, text for the content of the task and the name of the user who created it.

We create a instance of the standard JavaScript Date object to be used later.

We instance the Task Relation like we would instance an object from a class: new Task(). The “Task” refers to the accessor property we created for our prototype Relation earlier. The constructor takes an object as a parameter, which we can use to override built-in fields and assign or override custom properties. We give it a name “task” in lower case to denote that it is an instance, not a prototype intended for instantiation. We set the owner to the function context’s this, which is the tasks Entity. Finally we set the properties text and user to the given parameters and fetch the time from the Date object we created earlier.

The User Interface

The ui.vsx inside the client Entity is where we describe our entire user interface. It is slightly more complex than our Hello, World! example, but I will break it down for you below. As we won’t be addressing CSS styling in this tutorial, you can download the styles.css used in the tutorial from here.

Please note, that the file extension in Gist is incorrectly .jsx to get automated syntax highlighting. For VSX files the correct file extension is .vsx.

Let’s look at this in chunks:

We again start by wrapping our user interface into a <DIV> element and apply styling. We also hard-code a heading for our application.

Here we use another feature from our implementation of the JSX-Control-Statements: the <If> conditional. We can specify a test that will only render it’s contents if the test returns true. In the first <If> block we present the user a login form only if the user is null. Because our client Entity has the user set to null before we do the local instantiation, the first-timers will always be prompted with a login form. Inside this block we have the following for the actual login:

Every time the user writes something to the text field, the onKeyPress event listener will check if Enter (keycode 13) was pressed. If so, it will set the Property user to the value currently in the input field. Like in the Meteor example, we have left the password out.

The next <If> block renders only when focus.user is finally truthy and contains the rest of our user interface. We can set a context to an <If> block as well. It allows us to define values we want to remain constant during the rendering of the block. We shorten the focus.user to be accessible inside the block with just user and fetch all tasks to the tasks variable from the tasks Entity via our pointer using the familiar syntax focus.tasks[Relatable.getRelations](“task”). Note, that we write the “task” with a lowercase in order to list the instances created by our newTask.vs function, but not the prototype named “Task”.

Because <If> blocks support only one element as their child, we wrap the rest of the user interface to another <DIV> element.

Here we display the username and provide a link for signing out. In our implementation all we really do is set the current user to null. This causes both <If> blocks testing the focus.user value to refresh, the first now once more rendering the login screen and the second one no longer refreshing.

Here we provide a checkbox for the hideCompleted Property. We can make sure the checkbox is correctly checked by providing the value to the checked property.

With this input field our users can add new tasks. We do the same check for onKeyPress as with the login form, listening for the keycode 13. When Enter is pressed, we create a new task by traversing to the tasks Entity via the pointer and calling the newTask.vs function with the value of the input field and our current user. This will instance the Task Relation and create a new task. Finally we clear the input field with e.target.value = null;.

We use a list items to print our tasks. Inside the <UL> element we use the familiar <ForEach> utility to iterate through the tasks we set earlier in the context of our <If> block. We use a sort function to order the tasks from new to old.

This <If> block is used to determine if we show the iterated task at all. It checks if a) the task is not private or the user who created it is the user looking at it and b) the task is not done or the hideCompleted Property is false.

Here we again use a ternary operator to give our list item a class completed based on done Property of the task.

Next we have another simple checkbox for toggling the done Property of the task.

This <If> block is used to only allow the creator of the task to toggle the isPrivate Property of it. Here we create simple true/false toggle function for the isPrivate Property and render either “Private” or “Public” in the button using the ternary operator:

Here we render the creator and the content of each task.

And finally provide only the creator of the task a button to delete a task. Valaa.Resource.destroy() is a built-in function in ValaaScript for destroying any Resource. Quite permanently.

And that’s it.

This tutorial was partially made as a benchmark to see how Valaa matches with Meteor, a great JavaScript framework for building multi-user applications. Like Valaa, Meteor ships with pretty much everything you need to get an application up, running and delivered to the users with minimal amount of code.

I chose their excellent to-do application tutorial and see if I could achieve similar results with Valaa.

As a disclaimer — Meteor is a mature and widely used framework while Valaa is not (yet). We still lack some of the built-in features of Meteor, such as user-defined tests, user management and authentication. Our version looks and feels similar, but it is not secure.

--

--

Ville Topias Ilkkala
valaa.log

I work with companies, universities, research groups, nonprofits and foundations towards a digitally transformed society. I’m the co-founder and CTO of Valaa.