Studio 1
This studio has two goals:
- Teach you about design critique
- Practice VueJS so you can develop interactive UIs
Design critique
Two things:
a) Zara website
b) Hands-on design critique: Braun Age Precision Digital Stick
We will pass the thermometer around during the Vue exercise below, along with some alcohol wipes for those who need them. When it reaches you, take a few minutes to use it. Try to use it to take a temperature (don’t put it under your armpits or in your mouth! Just hold it in your hand tightly). What did you struggle with? How could it have been designed better?
Making a basic To-Do app
We will make a simple to-do list that:
- Displays number of done items and total items
- Allows you to delete items
- Allows you to add items
- Allows you to delete completed (done) items with one click
Then, if there is time, we will explore making usability improvements to our app.
You should open the Vue Cheatsheet as well as MaVue.
Step 1: Basic infrastructure
If you haven’t already, fork the studio1-starter
repo
and open index.html
in your local Visual Studio code editor.
Start a local server in that directory,
and open http://localhost:8000
(or whatever port you've specified) in your browser.
Step 2: Basic HTML
Add the basic HTML for a list of tasks with one sample item (with a checkbox for "done" and text field) and buttons to delete items, add a new item, and clear completed items. Just static HTML, don’t worry about it being functional yet!
Mini HTML cheatsheet for some elements you will need:
<h1>
-<h6>
<ul>
: Unordered list<li>
: Unordered list item<input>
<button>
(<input>
can also be used for buttons — don’t do that)
We will not be using <label>
here, since there is no visible label either,
but in general you should use labels for all your form controls.
If you want to add more context for screen readers,
but there is no visible text to wrap with a label,
you can also use the aria-label
attribute.
Step 3: Connecting the list of tasks to our HTML list
Right now, your HTML has one static item.
Let's start connecting our HTML to our data model.
Use v-for
to tell Vue to template one list item per task in the data model.
Type app.addItem()
in the console to make sure it works.
You should get an additional list item every time.
Step 4: Making the add button functional
If you look at index.js
, it already provides three functions for you that modify data:
addItem()
, deleteItem(i)
(and also clearCompleted()
, but don’t worry about that yet).
Use the @click
action to make the add button in your template functional.
Do not worry about the other buttons until the next step.
Step 5: Connecting the inputs with data
Type something in your to-do list and then type app.tasks[0]
in the console.
What do you see? It is still an empty object!
This is because we have not yet connected our checkbox and text field to the data.
Use v-model
to connect the done
and title
properties of each task to their corresponding form elements.
Make sure you use the variable you have specified for the current item.
If you write tasks.title
instead,
Vue will not give you an error because this is not technically an error:
it will think you just want to write the title
property on the tasks
array,
which in JS is a valid thing to do (though not what you want here).
In JS, arrays are also objects, and can have arbitrary properties,
in addition to their items (which hang on numeric properties).
Step 6: Making the rest of the buttons functional
Now hook up the "Clear completed" button and the delete item button,
with the clearCompleted()
and deleteItem(i)
functions respectively.
Note that the deleteItem(i)
function takes one parameter: the index of the item being deleted.
It will not work if you don’t provide any arguments.
Step 7: Showing number of items, and number of done items
Now let's display some statistics about our to-do list!
First, add something that shows the total number of items;
(array.length
is useful here).
Let's also count how many items are done, i.e. how many objects have done == true
.
We will use MaVue’s get()
function to get all done
values in one array,
and then the count()
function to count them.
Step 8: Persisting data locally
It’s not a very useful to-do list if every time the page is refereshed our tasks are gone!
Let’s use <ma-data>
to persist data locally, in the browser.
You can just use src="local:tasks"
to store your data locally in the browser under the tasks
key.
Make sure to also use autosave
, or have a button for saving, otherwise the component will not do anything!
Step 9: Improving efficiency
Now you have a fully functional to-do list, yay! Play around with it a bit, enter some tasks, mark some as done.
What do you notice? It’s a little annoying to use, isn’t it? You have to constantly switch from the keyboard (typing the task title) to the mouse (clicking on buttons, marking items as done).
In most to-do lists out there, there are established conventions for using them with the keyboard.
What are these and how can we implement them?
Show answer
One such convention, is that hitting Enter with the keyboard inserts a new item, and then focuses it.
You can use the keyup
event,
with an enter
modifier to do that.
This will insert new items when the Enter key is pressed, but they will not be focused.
You can use the v-focus
MaVue directive to make sure the text field on new items is focused
(the HTML autofocus
attribute sadly works on page load, not element insertion).
Going even further
This is entirely optional; it is much harder than the previous steps, and only for the brave souls that really want to dive in.
Another common convention is that backspace on an empty item deletes entries.
This is a trickier to implement, because you only want this to happen when the input is empty.
Also, managing focus becomes harder, because the elements that should receive it already exist,
so just using v-focus
without a value will not work.
You can try at home if you want to do this, but it's out of scope for the studio. Some key ideas for implementation are:
- You will probably need to add a new method in
index.js
,deleteItemIfEmpty(i)
- You will need to set
v-focus
to theactive
property, so you can manage focus by changing it - You will need to use
@focus
and@blur
to set theactive
property to the right item when inputs are focused, so that it's always current - You will need to make sure you focus the previous item after an item is deleted this way. Caveat: when deleting the first item, there is no previous item!