Reusable Components - Configuring Options

7. Lesson of RiotJS

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.

Martin Muzatko Written by Martin Muzatko
on

intro

We have some serious decision-making to do, to make our component as reusable as possible.

  • Do we just assume a property to exist?
  • Do we have another component attribute (opts.labels?) to tell what properties are shown in the picker and in the selected list?
  • Are there defaults? show first property of object as label? How do we determine them?

There are really a few decisions that can make or break a components reusability. Depending on if you prefer it to be easy to use or flexible or a bit of both.

For this lesson, we are going to decide the following: We don't assume for properties to exist, we will have another option to pass a list of labels, but this is not required. If the labels option is not present, we will just display all properties in the picker select, and the first property as label for selected picks.

JAVASCRIPT
this.labels = opts.labels || Object.keys(this.items[0])
this.mainLabel = opts.mainLabel || this.labels[0]

For the labels, to be flexible, we have two possible cases: if opts.labels does not exist: use the Object keys of the first set of items (in this case, we have to assume that the user is sane enough to pass an array of objects with always the same fields - empty or not). Displaying the Data - Nested Loops Because I get tired of writing data, I use mockaroo to create my test-data. Then we are going to switch over to tables to display our data. We can iterate them with a nested each. You can use the data of both loops.

RIOT
<table>
    <tr>
        <th each={label in labels}>{label}</th>
    </tr>
    <tr class={selected: item.selected} onclick={pick} each={item in items}>
        <td each={label in labels}>
            {item[label]}
        </td>
    </tr>
</table>

Here, we have a loop for the table-heading elements to display the labels, and below a more complex multiloop to display each item with the correct label. As you an see, we can copy the class and onclick attributes over, as they are not subject to change. Just a few additions to CSS and our item-picker looks magnificent.

Additionally, we also change the picked users to use the mainLabel.

RIOT
<div class="picked-items">
    <span if={item.selected} each={item in items}>
        {item[mainLabel]}
    </span>
    <input onfocus={openList} type="text">
</div>

The result is a much better reusable component with variable data.

<script type="riot/tag"> <application> <h2>Select authors for this lesson</h2> <picker items=\{lessonUsers\} labels=\{['name', 'email', 'country']\}></picker> <h2>Select developers to hire</h2> <picker items=\{lessonUsers\} labels=\{['name', 'job']\}></picker> this.lessonUsers = [ \{"name":"Jack Stevens","email":"jstevens0@cdbaby.com","country":"France","job":"Payment Adjustment Coordinator"\}, \{"name":"Teresa Lawson","email":"tlawson1@meetup.com","country":"Indonesia","job":"Computer Systems Analyst I"\}, \{"name":"Timothy Alvarez","email":"talvarez2@chicagotribune.com","country":"Russia","job":"Software Test Engineer I"\}, \{"name":"Ernest Lawrence","email":"elawrence3@google.com.au","country":"Philippines","job":"Software Engineer II"\}, \{"name":"Lois Patterson","email":"lpatterson4@forbes.com","country":"Indonesia","job":"Assistant Professor"\}, \{"name":"Tina Nelson","email":"tnelson5@ihg.com","country":"Myanmar","job":"Occupational Therapist"\}, \{"name":"Carlos Torres","email":"ctorres6@sfgate.com","country":"Mexico","job":"Analog Circuit Design manager"\}, \{"name":"Donna Henderson","email":"dhenderson7@liveinternet.ru","country":"China","job":"Safety Technician I"\}, \{"name":"Randy Grant","email":"rgrant8@blogs.com","country":"Japan","job":"Pharmacist"\}, \{"name":"Denise Campbell","email":"dcampbell9@illinois.edu","country":"Pakistan","job":"Analyst Programmer"\}, \{"name":"Pamela Cooper","email":"pcoopera@sitemeter.com","country":"China","job":"Software Engineer I"\}, \{"name":"Stephen Rogers","email":"srogersb@sogou.com","country":"Netherlands","job":"Payment Adjustment Coordinator"\}, \{"name":"Helen Powell","email":"hpowellc@accuweather.com","country":"United States","job":"Budget/Accounting Analyst III"\}, \{"name":"Fred Wheeler","email":"fwheelerd@marketwatch.com","country":"Portugal","job":"Staff Scientist"\}, \{"name":"Bonnie Bradley","email":"bbradleye@privacy.gov.au","country":"Thailand","job":"Engineer IV"\}, \{"name":"Michelle Medina","email":"mmedinaf@theguardian.com","country":"Nicaragua","job":"Physical Therapy Assistant"\}, \{"name":"Henry Howell","email":"hhowellg@mlb.com","country":"France","job":"Recruiting Manager"\}, \{"name":"Jose Ross","email":"jrossh@livejournal.com","country":"Ukraine","job":"Account Executive"\}, \{"name":"Jesse Hart","email":"jharti@joomla.org","country":"Republic of the Congo","job":"Community Outreach Specialist"\}, \{"name":"Margaret Simpson","email":"msimpsonj@de.vu","country":"Russia","job":"Database Administrator III"\}, \{"name":"Carol Warren","email":"cwarrenk@devhub.com","country":"Japan","job":"Media Manager III"\}, \{"name":"Shirley Ray","email":"srayl@ca.gov","country":"Russia","job":"Marketing Assistant"\}, \{"name":"Kenneth Wood","email":"kwoodm@google.fr","country":"Indonesia","job":"Junior Executive"\}, \{"name":"Ruth Bailey","email":"rbaileyn@zimbio.com","country":"France","job":"Design Engineer"\}, \{"name":"James Morales","email":"jmoraleso@aol.com","country":"Honduras","job":"Senior Sales Associate"\}, \{"name":"Bobby Bradley","email":"bbradleyp@webeden.co.uk","country":"Philippines","job":"Environmental Specialist"\}, \{"name":"Peter Henry","email":"phenryq@printfriendly.com","country":"Vietnam","job":"Budget/Accounting Analyst III"\}, \{"name":"Benjamin Banks","email":"bbanksr@prlog.org","country":"Peru","job":"Teacher"\}, \{"name":"Stephanie Kelley","email":"skelleys@mayoclinic.com","country":"China","job":"Recruiting Manager"\}, \{"name":"Roger Wells","email":"rwellst@google.com.hk","country":"China","job":"Safety Technician III"\} ] </application> </script> <script type="riot/tag"> <picker> <div class="picked-items"> <span if=\{item.selected\} each=\{item in items\}> \{item[mainLabel]\} </span> <input onfocus=\{openList\} type="text"> </div> <div if=\{isPicking\} class="picker-list"> <a onclick=\{closeList\}>&times;</a> <table> <tr> <th each=\{label in labels\}>\{label\}</th> </tr> <tr class=\{selected: item.selected\} onclick=\{pick\} each=\{item in items\}> <td each=\{label in labels\}> \{item[label]\} </td> </tr> </table> </div> <style> .picker-list a \{ position: absolute; cursor: pointer; font-size: 1.25em; right: .5em; top: .5em; \} .picker-list \{ position: relative; display: inline-block; background: #EEE; \} .picker-list table \{ cursor: pointer; margin-top: 1em; \} .picker-list table tr:nth-child(odd) \{ background: #DDD; \} table td \{ padding: .4em; \} .picker-list table \{ border-collapse: collapse; \} .picked-items span \{ margin-right: .5em; margin-bottom: .2em; padding: .1em; display: inline-block; \} .selected, .picked-items span \{ background: #3377B5; color: #F1F1F1; \} .picker-list .selected:nth-child(odd) \{ background: #4488C6; \} 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 this.labels = opts.labels || Object.keys(this.items[0]) this.mainLabel = opts.mainLabel || this.labels[0] </picker> </script> <application></application>

Summary

Are you still there? Since last lesson you learnt nothing really new, other than applying our new knowledge in a more complex context. You see where just a few simple tools can get you. The next few lessons will be an addition to the picker, but we will use what we already know. Eventhandling, Looping, Expressions, Conditionals,... etc.

Filtering, Sorting and a lot of other features of the picker are not more, than a new composition of the above elements we already know.

If you don't manage to keep up with the fastpaced lessons, please drop a comment in the box below, and I'll answer your questions.

So long,
Happy coding!

Do you need inspiration how to solve those tricky issues? Issues that when resolved once and for all, would ease a lot of daily user interface interaction.

Get on my list! You are invited to reply to any email with your important questions and get a hand-crafted reply with hands-on guides. You will learn how to solve your individual use-cases. Fill in your name below and get in touch today :) . It is about a nice conversation from developer to developer after all.

Previous Lesson

Reusable Components - Introduction

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.

Next Lesson

Reusable Components - Reusable Features

We are going to implement a filtering feature and later we will turn that into a reusable mixin.

See all Lessons