by

Custom Alloy view components

This morning I was trying to use Appcelerator’s Styled Label Module in an Alloy project and discovered how Alloy’s namespace feature can be used to create custom Alloy view components.

Update: As of Alloy 1.2 you would use <MyView module="my/factory" /> which would result in require('my/factory').createMyView().

The iOS example included in the project shows the view component should be used like this:

So how do we do this in Alloy?

Well, by default Alloy takes a view component’s tag name and prepends Ti.UI plus .create, so that Label becomes Ti.UI.createLabel. Luckily, the Styled Label fits the second convention, but instead of Ti.UI, we need StyledLabel.

Alloy Namespaces

This is where Alloy’s namespaces or the ns attribute comes in. Meant to be used for views like Ti.Map.View it let’s you specify what needs to be used instead of the default Ti.UI, where most of Titanium’s builtin view components can be found.

So let’s define our view code:

And of course in our controller we need to require the module:

And there you are, it looks like we’re done:

.. but we’re not! Try to run this code and you’ll get our beloved red screen telling you Can't find variable: StyledLabel at...

Understanding Alloy

But didn’t we defined this variable in our controller? Yes we did, but if you open the Alloy compiled controller you will see that all the generated view code is placed before the original controller code. So at the time our Styled Label is created, there is no StyledLabel variable, hence the error.

I’m sure some day we will be able to specify parts of our controller code that needs to come before the view code, but right now we can’t.

Working around

Of course StyledLabel was just a arbitrary name we picked. What we really need is a reference to the ti.styledlabel module. Knowing now how Alloy used the ns attribute, the solution is actually pretty simple:

which translates properly and works as:

As an alternative you could define StyledLabel in alloy.js, which will get inserted in the generated app.js. This pollutes the global scope, but now you can just use StyledLabel as namespace.

Custom view components

The require construct can be used to require native as well as CommonJS modules. This opens up possibilities for easily adding custom view components. Imagine having the following loremipsum.js CommonJS module:

Now this can be used in an Alloy view like this:

You’ll end up with a custom Alloy view component that shows a variable amount of Lorem Ipsum in a label. Of course this could also be a view composed out of several children, with event listeners and whatever functionality you can think of. Think of it like or but then for stand-alone CommonJS modules.

You can even add child elements like this:

This will generate code calling someView.add to pass the child views, something that isn’t (yet) supported for Widgets.

Pretty awesome hey?!