tabris typescript

Tabris Decorators Part 2: Introducing Tabris Components

NOTE: This article is about Tabris 2.x. Some information is outdated when targeting Tabris 3.x.

In this article, we will cover how TypeScript decorators are used in the Tabris Framework to create UI Components. It is a part of the blog post series dedicated to the Tabris.js extension called tabris-decorators, which makes developing mobile apps with Tabris.js 2.x and TypeScript more convenient. The extension features data binding capabilities, enhanced event handling and dependency injection, explicitly designed for the Tabris mobile framework. To use it the npm module must be installed separately.

If you want to know more about TypeScript Decorators in general, what they are, and what benefits they bring to your work, please see our Introduction blog post here.

What is Tabris Component?

A Tabris component, for the purpose of this text, is any TypeScript class that extends Composite, Page or Tab and uses the @component decorator. To write your first component, set up a Tabris 2.x project with tabris-decorators as described here.

For our main example, we will write a simple LabeledInput view that consists of a TextView (the label) and a TextInput described by it. That may be useful in forms where you would need this combination over and over again.

Let’s start just with the visuals:

This creates just children with same placeholder text. Notice the @component decorator above the class definition.

The jsxProperties field is required for the compiler to know which attributes are valid when using this widget as a JSX element. It’ll become relevant when we discuss event handling.

Okay, so this should already work to some degree. Import the component in another module and add it to the main content view:

Okay, but…

What does the @component decorator actually do?

You can find the full documentation here, but for now, we are looking at how it encapsulates the component.

Consider this code:

The intend here is to hide the first LabeledInput, but without @component it would actually also hide all the textInput elements inside all the other LabeledInput instances. The decorator makes the component behave to the outside as though it had no children, a bit like the shadow DOM in HTML. Here’s the proof:

Of course we still want to be able to access and manipulate the children from the inside of the component, which is possible via protected API dedicated to this use case:

Aside from _find there is also _apply and _children. However, you will rarely need any of those, as we will discover in the chapters on data binding. For now, just remember to always use the protected API instead of the public one and you will be fine.

Coming up…

The encapsulation aspect of @component is a convenient safeguard against accidental name collisions of id or class, but it’s not its main purpose. What we really need it for, is data binding which we will discuss in the next chapter. See you then!