Building Re-usable Components In Alloy

0 Flares 0 Flares ×

Titanium + Alloy is the fastest way to develop cross-platform, native mobile apps. Not only does Alloy use a Model, View, Controller paradigm (MVC), it also comes with features like theming, platform-specific resources and re-usability.

In “classic” Titanium, you could re-use libraries of code using the Ti.include method, which would add another JavaScript file into a project. This was a quick and simple way to add functions and additional capabilities into a project. The problem was that this method could lead to lots of include files being added, nested includes, and could easily lead to memory leaks and performance issues.

Once Titanium added CommonJS support, Ti.include was eventually removed. CommonJS provided a simple way to create isolated, memory safe libraries that couldn’t pollute the global scope of JavaScript and lead to other issues.

Typically, you can add in a CommonJS file by adding referencing it as:

var foo = require(“bar”);

which would load in the bar.js file from the resources or lib folder, and assign this to the foo variable. If the bar library contained this:

exports.helloWorld = function(){
	alert(“Hello!”);
};


then calling foo.helloWorld() in this case would display an alert. Simple.

What’s great about CommonJS is that each module is isolated, so if you were to accidentally create a global variable it would not pollute the main app.

More importantly, each module is referenced as a pointer. This means if I required a module and set some state within it, and then I required it elsewhere, it would create a pointer to the originally required module meaning I could access its state from anywhere. Ideal for creating config / global settings.

When Alloy came along, it implemented CommonJS for controllers, views etc. So, adding a new controller with Alloy.createController is instantiating a new instance of a controller as a commonJS module using the new keyword.

We covered this in a previous post about AlloyXL, a library that can override the Alloy.createController method to add additional events and clean-up features.

When developing with Alloy, using the MVC approach, there are times when you want to create components that can be re-used, whether in the same project or other projects you are working on. You might also want to create open-source libraries that other developers can use.

Let’s look at the various ways you can create fully reusable components in Alloy.

Firstly, let’s clarify what re-usable means, as I’ve seen examples of components that should be re-usable, but when you try to use them in other projects, or separate them from the project they are in, they break.

In order for something to be re-usable, it needs to:

  • be self-contained
  • manage its own state
  • manage its own styling
  • manage its own configuration and settings

What does this mean in practice?

Well take for example a calendar control that might be written for a project. It might have several different settings and how it appears on the screen (in a pop-over on iPad, or as a picker on iPhones or as a full screen element). It might also need to be styled for colour, headers, fonts etc.

All of these aspects of the control need to be editable but shouldn’t be linked to the parent app.

NOTE: I’ve seen examples of Alloy Widgets etc that are styled using global styles or linked to assets in the host application. This means they’re not fully re-usable and you need to have those assets available in any project it’s used in which isn’t ideal.

So, given we’re trying to create something completely re-usable, independent and installable into any project, let’s look at how we can do this in Alloy.

Widgets

Alloy “Widgets” are the best way to create completely re-usable visual components that can be dropped into other Alloy projects:

  • Widgets are like mini Alloy applications. They comprise of the same MVC structure as a main Alloy application. So, you have a widget.js, widget.xml and widget.tss file (you can add others), and so all the coding and styling methods you’re used to in Alloy are used in Widgets. They can use TSS, they can use platform-specific resources and they support theming.
  • Widgets can be packaged into a single compressed file, and hosted in an open-source or other repository, and installed using the gitt.io CLI which will not only uncompress the widget into the app/widgets folder but add the dependancy information to the config.json file.
  • A widget can consist of a single component like a calendar control or could be a complete library of UI components and each can be implemented within in the XML views.
  • Widgets can be added to XML files or instantiated in controllers with JavaScript.
  • Widgets can have their own assets / resources; html files, images, icons, fonts. They can be packed with everything they need to work independently of the host application. They can also access files in the host application if required.

Required Views / Controllers

An alternative to Widgets is to create controllers / views within your project and require them into your application.

These have a similar structure to Widgets as they would consist of a View, Controller and Style file but instead of being packaged in a Widget, they’re just added to your application normally.

Typically, when I use this method I put them in a “fragments” folder under my View, Controllers and Styles folders. I might use this when I have to create something that’s reusable but it’s integrated into the host application and isn’t fully usable anywhere else, so this might be a view that you need to include in different parts of your app but its design, layout and functionality is closely tied to the parent app.

In order to use one of these “fragments,” you would either create an instance manually, in JavaScript:

var fragment = Alloy.createController(“fragments/calendar”);
$.getView().add(fragment);

or within an XML view:

<Alloy>
  <Window>
    <Require id="calendar" src="fragments/calendar"/>
  </Window>
</Alloy>

In this example, you can access the required controller by using $.calendar in the parent controller file and of course interaction with it can be via direct access or using $.trigger and $.on.

Custom Alloy Tags

This is one of my favourite ways to create re-usable components within Alloy applications. By using CommonJS modules, you can create your own tags, override tags or add more functionality to existing Alloy tags.

The beauty of this approach is that you can have a single CommonJS file that can be added to a project and by adding a single attribute to a tag, be it the tag itself e.g. TextField or the Alloy tag itself, all your existing tags in a view will start using your custom code.

For example, create a commonJS file called “ui.js” in the lib folder containing:

exports.createView = function(args){
  var view = createView(args);
  return view;
}


Create a simple view:

<Alloy module="ui">
  <Window>
   <View/>
  </Window>
</Alloy>

In this example, when Alloy creates the View tag it’ll try the ui.js file first, looking for a createView method. If it finds it, it’ll use that and if it can’t, it’ll fall back to the default method.

This means the code above is being called to create the view, and that means you can do all kinds of things to that element before returning it. You might want to set some defaults, or add some custom methods or properties, or in the case of cross-platform development, you might make a component work a completely different way on Android.

There’s a great example on how to redefine the NavigationWindow component so it can be used on both iOS and Android. In that, I override the standard tag to make it return a normal component for iOS, but work in a custom way on Android. That means there’s no need to create conditional XML, or separate XML views.

Other ways you could use custom tags is to add additional functionality to elements — for example, you might want to include some basic validation, based on either a function / method or a wildcard, for validating a TextField. In this case, you could add the functionality to validate the field within the CommonJS library used to create it.

I’ve used this recently when creating forms within apps. I designed a <Form> tag, which can wrap a series of controls and has some additional capabilities:

  • it automatically has as vertical layout
  • it can auto-populate fields, controls contained with default values
  • it can return all the values of its children as a JSON object on demand
  • it can handle its own validation

The result was a really simple element I could add to a view to create a quick form and get the values back. Any time I add a new TextField within the form, all I have to do is give it an id and that’s it. When the submit button is pressed the form returns its name and valid as part of the form JSON data. If I pass a JSON object to the form element, then it iterates through the values, and populates the fields automatically. The result is less to no code in my controller files which is always good!

One More Thing

In addition to the methods above, you can also add NPM packages to Titanium apps, and there’s a good post where this is explained in detail.

if you’re looking to create native components or access native elements in a mobile SDK not exposed by Titanium, then there’s native modules, and of course Hyperloop. Native modules are built and compiled for each platform in either Objective-C (soon Swift) and Java, and in Hyperloop you’re coding directly to the underlying SDK with JavaScript. Again, check out gitt.io — a great resource for modules.

Finally there’s also ES6, and using ES6 modules, and we’ll be creating more posts on that soon. In the meantime, check out the Kitchen Sink 2 demo app, updated to use ES6.

Have you got any other tips and suggestions on building re-usable components for Titanium and Alloy? Drop a comment below and let us know.

Happy Coding!

0 Flares Twitter 0 Facebook 0 Google+ 0 LinkedIn 0 Email -- 0 Flares ×

Leave a Reply

Your email address will not be published. Required fields are marked *

Sign up for our blog!

computer and tablet showing Appcelerator software
Start free, grow from there.
0 Flares Twitter 0 Facebook 0 Google+ 0 LinkedIn 0 Email -- 0 Flares ×