Titanium Basics: Make a reusable component and talk to it

Rene Pot
All Titanium

--

So, a lot of times you want to use a component in your app that you can re-use in your entire app. For example, a custom button. So how do you set this up, and how do you get it to work properly throughout the app.

First of all, there are 2 methods of creating reusable components.

  1. Widgets
  2. Controllers

I personally believe widgets should be used for elements that can and should be used in multiple apps. Preferably even open sourced. If this is not the case, make a controller instead.

Widgets should also not have dependencies from the app it is included in, like global variables (Alloy.Globals) or config properties (Alloy.CFG). I rarely use Widgets myself because most elements I create will never see another app. This blogpost will also not dive into creating & using Widgets, instead we’ll just talk about a reusable controller.

Create the Controller

When creating a controller name it properly. In this case we’re creating a button that is to be used throughout the app. So, I would recommend putting the button controller in a folder. Example

/app/controllers/components/button.js

If you use Appcelerator Studio you can create a controller by right-clicking inside your project and choosing New > Alloy Controller and within the modal you type components/button which will create the controller inside the folder, and create the folder if it doesn’t exist yet. With the CLI you can create a controller using:

alloy generate controller "components/button"

Both cases will not just generate the .js file, but also the .xml and .tss files. All in the same place.

Building the Controller

Just making the controller very simple we’re going to make it a view with a nested label. Basically what the <button> element already is, but now custom. This allows you to expand on functionality later.

//button.xml:
<Alloy>
<View id="buttonWrapper">
<Label id="buttonText" />
</View>
</Alloy>
//button.tss:
"#buttonWrapper": {
left: 20,
right: 20,
top: 20,
bottom: 20,
height: 50,
backgroundColor: "#216355"
}
"#buttonText": {
color: "#ffffff",
font: {
fontSize: 30
}
}

Implementing the button

The above code basically is a button. It doesn’t do anything yet but we’ll get to that. First, we’ll need to be able to set the text of the button. In this example we’ll use the default index controller to implement the button.

//index.xml:
<Alloy>
<Window class="container">
<Require src="components/button"></Require>
</Window>
</Alloy>

This will put the button into your window and work out of the box. Now to setting the button text. We’ll to this by first adding an id to the element.

<Require src="components/button" id="button"></Require>

Then in index.tss we’ll add the button text:

"#button": {
text: "Button Title"
}

Now this on its own does nothing at all, because the button component doesn’t know what to do with the text. So when diving into button.js you can assign how to handle it. All properties you set in index.tss or index.xml on the element will be passed into arguments. All arguments are available through $.args

if ($.args.text){
$.buttonText.text = $.args.text;
}

This will apply the text provided in index.tss to the button label.

Listening to the component

Next step is to make the button work. What you’ll need is a click handler. This is also pretty easy. Lets take the button.xml view and adjust it to this:

<View id="buttonWrapper" onClick="clickButton">
<Label id="buttonText" />
</View>

Now add the clickButton function to button.js and let the event be bubbled up:

function clickButton(e){
$.trigger('click', e);
}

This function will bubble the click event up to the next level. Now all we need to do is watch this event using on in index.xml:

<Require src="components/button" id="button" onClick="clickButton"></Require>

Now within index.js you can make the function clickButton and it will fire when the component triggers the click. Because you have full control over all elements, instead of triggering the click event you could’ve made something custom:

function clickButton(e){
$.trigger('myRandomName', e);
}

In index.xml you could’ve watched for this event like this:

<Require src="components/button" id="button" onMyRandomName="clickButton"></Require>

As you can see. All you need to do is capitalise the first character of your event name and add on in front of it. You can also trigger an event whenever you want, you don’t have to wait for user input.

Talking to the component

Now you know how the component talks to you, you will also need to know how to talk to the component. Lets say you want to be able to change the backgroundColor of the button. You would add this to button.js:

function setBackgroundColor(color){
$.buttonWrapper.backgroundColor = color;
}

Now, this function isn’t accessible from the index controller. It can be accessible with 1 extra line:

exports.setBackgroundColor = setBackgroundColor;

Now you can set the color from index.js simply by calling the function

$.button.setBackgroundColor("#581D42");

With the combination of talking to a controller and listening to it, you can go as crazy as you want.

--

--