Tutorial: Building a ToDo app with OOjs-UI (Part 2)

In the previous part of this tutorial, we walked through how to make a very basic version of a ToDo app using Wikimedia’s OOjs UI library. Now it’s time to add a way to store and display information from our items.

This post and the accompanying code is available on Github. Corrections and pull requests are welcome!

Displaying info

Let’s first create a way to view the information we have about our items. We’ll start by adding a simple label to our page:

Once again, we’re adding a widget, and appending its $element to the DOM. Now we can use it to display the information stored in our widget. The ToDo items all live inside an OO.ui.SelectWidget which emits a ‘choose’ event when an element is clicked or chosen, with the reference to the chosen item as the parameter. We’ll attach a listener to this event.

Now we have a very simple way of presenting the data stored in our item. This is a good start, but it doesn’t yet seem to be all that helpful, because the data stored in each of our items is the same as its label, and doesn’t quite give us any useful information. Let’s change that now.

Creating a custom item widget

In order to expand the functionality of the OO.ui.OptionWidget so we can store more information, we need to create our own class and extend OO.ui.OptionWidget.

Create a new file in your assets/ directory, called assets/ToDoItemWidget.js. In it, we are creating our new class:

Our new function extends OO.ui.OptionWidget, by declaring OO.inheritClass( ToDoItemWidget, OO.ui.OptionWidget ); and by calling the parent constructor in the new class’ constructor.

Before we start actually defining members of this class, let’s make sure we can use it in our code. Let’s reopen index.html again.

First, add the file:

Second, change the code to use the new ToDoItemWidget class:

You can try out your app again, but nothing should be different just yet. We can now start developing our new class to add the functionality we want to have.

Adding functionality

Let’s add a property that stores the creation time of our todo item.

Now we can set this when we instantiate the object in our initialization script, and change the info label to display this new property.

Okay, that works, but since Date.now() is a UNIX timestamp, it looks weird. Let’s make a better method to display it.

In ToDoItemWidget.js:

In index.html:

And now it looks much better.

But we’re not done. We’ve already enhanced the items, so let’s add some real functionality in there.

Adding a ‘delete’ button to items

Another of OOjs UI’s concepts is componentization – the ability to create bigger widgets from smaller ones. This can be pretty powerful and allow for advanced functionality.

We’re going to start small. Let’s add a ‘delete’ button to our list of items. You can read about what OO.ui.ButtonWidget expects in its configuration options in the official documentation.

In our ToDoItemWidget.js we’ll add a button:

Just like any other widget in OOjs UI, OO.ui.ButtonWidget has the $element property that contains its jQuery object. We’re attaching that to our own widget.

If you look at your app now, though, you’ll see that the button appears under the label. That’s because we need to add styles. Since we’re building our own widget, let’s do things properly and add a standalone style for it that we can then add and tweak in our CSS rules.

And the CSS rules:

There, that looks better. Now, let’s add functionality to this button.

Aggregating events

One of the best things about using a OO.ui.SelectWidget for our list, is that it uses the OO.ui.mixin.GroupElement that allows for really cool operations on a group of items.

One of those operations is an aggregation of events.

In effect, we can have each of our items emit a certain event, and have our list aggregate all of those events and respond whenever any of its items have emitted it. This means our logic can live “up” in the parent widget, consolidating our work with our items.

This means, however, that we will need to enhance our list object. We are going to do exactly what we did for our items (by creating the ToDoItemWidget class) but with a new ToDoListWidget class that extends OO.ui.SelectWidget.

Creating a ToDoListWidget

The new file ToDoListWidget.js:

Attach it to index.html and change the initialization code:

Responding to aggregation of events

Now that we have our ToDoListWidget we can aggregate its item events.

So how is it actually done? First, let’s have our button emit a “delete” event for our item:

Notice that this time, we didn’t use .on( ... ) but rather .connect( this, { ... } ) – this is because we are now connecting the object we are currently “in” the context of, to the event. I’ve used “on” before when we were in the general initialization script, and had no context to give the event emitter.

The string ‘onDeleteButtonClick’ refers to the method of the same name. When ‘click’ is emitted from that button, that method is invoked. It, in turn, will emit “delete” event.

Now, we need to make sure that the list is listening to this event from all of its sub-items. We will first aggregate the event and then listen to the aggregated event and respond to it:

We’ve used this.aggregate() to tell the group which events to listen to in its items, and we’ve used this.connect( this, { ... } ); to connect our own object to the event we aggregated.

Then, the responding method (onItemDelete) removes the item from the list.

You can now add and remove items from your ToDo app, yay!

The complete code

Future development and tutorials

Now that the app has basic operations, we can call this part of the tutorial over. I hope that you got a good taste as to what OOjs UI is like, and the potential it holds in quickly – but efficiently – developing JavaScript apps.

If you have any questions, concerns or corrections, please let me know in the comments. The entire code for this demo – and the text of the tutorials – is available in a GitHub repo, and pull requests are absolutely welcome.

In the next tutorials I will focus on the more advanced features of OOjs UI, like dialogs, advanced button-sets and working with a view-model to help us manage the operations in the background.

Until next time, JavaScript responsibly.

Tags: , ,

Trackback from your site.