Reusable Components - Introduction

6. Lesson of RiotJS

Previous lesson, we turned a bunch of data, some events and a simple HTML layout into a working app. Now we are going to take that a step further and make it reusable.

Martin Muzatko Written by Martin Muzatko


What makes a component a component?

Definition: A component is a module, that can be easily reused by passing different data to it. Or to put it in other words: We have to look for interchangable data. Objects, Arrays, Settings that have to be changed, in order to work for another usecase. Also: The "end-result" - the picked data, has to be usable from the outside. To, for example save to a database or whatever, the data belongs to you - you decide what to do with it.

Our picker could be used for a couple of things:

  • Picking Tags (to tag Posts or Products, like I do in the footer of this lesson)
  • A list of Items (Users, Emails, ...)
  • Some attributes, like size: tiny, medium or large to a product you sell in a product backend setup.
  • A rating (1-5 stars)

We could use the picker for a fixed range of values but we couldn't dynamically add new values. We could dynamically populate our values through ajax.

There are some other possibilities for our picker to be used for, but that requires a set of options to configure our component.

  • Allowing whether or not to dynamically add new items
  • Allowing to sort/filter items
  • Picking One or Many (for a rating of something, you would allow only one to be picked)
  • An option to have the Picker always open, picked data gets only highlighted. This could be especially useful, if we have a modal just for that and you don't want the user to click a couple of times to get to his selection.
  • Picking or deselecting all available items with one button

So, making a component really useful and reusable for all different possible usecases can take some time. But just think about this: If you need something like this in any piece of software ever again - you can reuse it! You just have to configure it and pass the data to it and you're set, but before we get there, there is work to do.

Enough chit-chat. Lets divide this into more lessons to come:

  1. Using variable data
  2. Passing options to configure the component (sortable? filter? dynamic adding? always open? labels?)
  3. Using the result data - listening and firing events on a component level.

Using variable data

In Riot, you can pass data to custom tags by using the second attribute of the mount function, or with HTML attributes.

<picker items={users}></picker>

Because we need to get the data from somewhere, we have to mount picker as a sub-tag. We create our core/main/hub tag to control everything from there.

    <h2>Select Authors for this lesson</h2>
    <picker items={lessonUsers}></picker>
    <h2>What does this lesson describe best?</h2>
    <picker items={lessonTags}></picker>
        this.lessonUsers = [
            {name : 'Martin Muzatko'},
            {name : 'Tero Jackson'},
            {name : 'Johannes Linz'},
            {name : 'Elias Backstein'}
        // tags is a reserved word for children-tags! 
        this.lessonTags = [
            {name : 'Easy'},
            {name : 'Quick'},
            {name : 'Enjoyable'},
            {name : 'Tough'},
            {name : 'Slow'},
            {name : 'Boring'},

In the picker, we remove the fixed data - the users and pass them as HTML items attribute.

We can use any name for these attributes: data, items, entries. There are no limits other than the reserved keywords, which are: opts, parent, root, update, unmount, on, off, one and trigger.

In the picker, we can retrieve data given by the custom tags attributes with this.opts. Since we decided to make this picker as generic as possible, we don't assume that those items are users. So we are going to rename every occurence of user to item in the picker to make it clearer that we are dealing with flexible data now.

To use the data passed in the picker tag, we can grab the data with this:

this.items = this.opts.items

We need to adapt our events to the current change from user to item too. This can lead to something as weird as event.item.item when we rewrite part of the events. Also we have to think about what properties of an object we show. We just can't assume name and email to be in place. Phew there is a lot to do.

First I show you, what the picker looks like when we assume that there is only one property: name. The more complex display of variable amount of labels follows in the next lesson.

<script type="riot/tag"> <blog-create-post> <h2>Select Authors for this lesson</h2> <riot-picker items=\{lessonUsers\}></riot-picker> <hr> <h2>What does this lesson describe best?</h2> <riot-picker items=\{lessonTags\}></riot-picker> this.lessonUsers = [ \{name : 'Martin Muzatko'\}, \{name : 'Tero Jackson'\}, \{name : 'Johannes Linz'\}, \{name : 'Elias Backstein'\} ] // tags is a reserved word for children-tags! this.lessonTags = [ \{name : 'Easy'\}, \{name : 'Quick'\}, \{name : 'Enjoyable'\}, \{name : 'Tough'\}, \{name : 'Slow'\}, \{name : 'Boring'\}, ] </blog-create-post> </script> <script type="riot/tag"> <riot-picker> <div class="picked-items"> <span if=\{item.selected\} each=\{item in items\}> \{\} </span> <input onfocus=\{openList\} type="text"> </div> <div if=\{isPicking\} class="picker-list"> <a onclick=\{closeList\}>&times;</a> <div class=\{selected: item.selected\} onclick=\{pick\} each=\{item in items\}> \{\} </div> </div> <style> .picker-list a \{ position: absolute; cursor: pointer; font-size: 1.25em; right: .5em; top: .5em; \} .picker-list \{ position: relative; display: inline-block; padding: 1em; background: #EEE; \} .picker-list div \{ cursor: pointer; padding: .1em; margin-right: 2em; \} .picked-items span \{ margin-right: .5em; margin-bottom: .2em; padding: .1em; display: inline-block; \} .selected, .picked-items span \{ background: #3377B5; color: #F1F1F1; \} input \{ display: block; \} </style> this.isPicking = false openList() \{ this.isPicking = true \} closeList() \{ this.isPicking = false \} pick(event) \{ event.item.item.selected = !event.item.item.selected \} this.items = opts.items </riot-picker> </script> <blog-create-post></blog-create-post>


So far we made the component reusable by passing differnt data to it via HTML attributes. Also we created a tag-hub (called application) that serves as our entry point to reusable components. Next up: Making the component configurable through additional opts.

Lost track on where we are going? Refresh your knowledge with the Riot Cheatsheet or leave a comment below. I'm always there if you need some help.

Previous Lesson

Do something! - Working with Events

Mastering Events is comparable to learning how a Spacerocket works inside out. Riot decided to rebel against this profession of event-wizardry and made it easy for everyone.

Next Lesson

Reusable Components - Configuring Options

Options can be used for a lot more. We can accomplish a variety of usecases with just a few options. Keep a close eye, as we proceed at a faster pace.

See all Lessons