Use custom element types to get more out of the type selector

In version 0.2, a system for states, much like CSS classes, will be fully supported. But until then, if we want to simplify selection subsets of similar elements, creating a custom element type is a quick and simple way to give us this ability.

First off, this guide is based on version 0.1 of Adamantium.js, so beware that the syntax, keywords and methods are not set in stone and may break between releases. If you haven’t already downloaded Adamantium.js, you can find it here.

The basics

Okey, so let’s start by fleshing out the requirements. Say we are building an app with a lot of ImageViews and where some of these ImageViews are “grouped”, in the sense that they share attributes and behavior, other than the defaults. This could be any app, but let’s say this is a social app where we need to differentiate user avatars from ordinary images.

$.push('UI.AvatarImage', function (args) {
	args = args || {};
	var element = Ti.UI.createImageView(args);
	return element;
});

We use the core framework method $.push() to store our custom element constructor in the central repo and if no arguments are provided, we create an empty object to use instead. After that, create the element using Titaniums factory construction method and return it to the caller.

This piece of code needs to be in your app.js, before you import any Screens that uses it. You could also place this code in a separate file, called “UI.AvatarImage.js” and pull it into your app.js, using the framework core method $.pull(). An example of this is found in the Adamantium.js example app source.

With this little code in our app, we could use AvatarImage type as a type selector.

$(":AvatarImage").load(function (e) {
	alert("Yay, " + e.source.id + " was loaded");
});

Why aren’t we using Adamantium.js syntax to create the new element? Well, the short story is that it wouldn’t work very well, as the element would be tracked twice, both as ImageView and AvatarImage types.

Default arguments

Most of the time when we create a custom element constructor, we would want this element to have default arguments, which would be used as arguments if no arguments were provided when constructing the actual element. This is as simple as you would imagine – just list your default arguments.

$.push('UI.AvatarImage', function (args) {
	args = args || {};
	args.width = args.width || 100;
	args.height = args.height || 150;
	args.borderRadius = args.borderRadius || 5;
	args.image = args.image || 'img/defaultAvatar.png';
	var element = Ti.UI.createImageView(args);
	return element;
});

Pre-defined arguments

In some use cases, as with this one, we would like to use our pre-defined arguments and not let provided arguments change the look or feel of the element we return. Our AvatarImage is a good example: the height and width for this element shouldn’t be optional, but should always be the same size. Implementing this is as just a matter of not listening to provided arguments, but setting the argument in the element constructor yourself.

$.push('UI.AvatarImage', function (args) {
	args = args || {};
	args.width = 100;
	args.height = 150;
	args.borderRadius = args.borderRadius || 5;
	args.image = args.image || 'img/defaultAvatar.png';
	var element = Ti.UI.createImageView(args);
	return element;
});

This that does not mean, however, that the height and width attribute of the element cannot be manipulated using the .attr() method after the element has been constructed, but any new AvatarView will always be the this size.

Exclude subset of elements

This example could also be used the other way around – if you had a subset of elements that you wanted to exclude from their inherent element type, you could make them a custom type. This way, whenever selecting the original element type, the custom type elements would not be included in the matched set.