A Component Mixin is a way to supplement an existing Tapestry component with additional behavior.
Wiki Markup |
---|
{float:right|background=#eee} {contentbylabel:title=Related Articles|showLabels=false|showSpace=false|space=@self|labels=component-classes,mixins} {float} |
You can think of a mixin as a kind of mashup for a component; it combines the behavior of the mixin with the behavior of the component, and bundles it all in one place. Mixins may be used to add validation to user input fields, or to add Ajax effects and behaviors to all sorts of components.
Tapestry comes with several mixins, such as the Autocomplete mixin which adds autocomplete behavior to an ordinary TextField Component. In addition, you can easily create your own.
Mixin Classes
Mixin classes are stored in the mixins
sub-package of your application, below the application (or library) root package. This parallels where your component and page classes are stored.
Other than that, mixin classes are the same as any other component class.
Mixin Limitations
Currently, mixins are allowed to do anything a component can do, including having parameters and render phase methods.
Mixins may not have a template. They integrate with the component strictly in terms of invoking render phase methods.
Mixins may have persistent fields, but currently, this is not implemented perfectly (there is a potential for a name clash between a mixin and the component or another mixin). Use persistent fields with mixins with care ... or better yet, delegate persistence to the container using parameters.
Mixins may not, themselves, have mixins.
Using Mixins
Mixins are used in two different scenarios: Instance mixins and Implementation mixins.
Instance Mixins
An instance mixin is a mixin applied to a specific instance of a component. This can be done in the component template with the mixins
attribute of the component tag. This is a comma-separated list of mixin names.
Code Block | ||||
---|---|---|---|---|
| ||||
<t:textfield t:id="accountName" t:mixins="Autocomplete,DefaultFromCookie" /> |
Alternately, when the @Component annotation is used to define the component type, you may specify the mixins in two ways:
- The @Mixins annotation allows a list of mixin names to be specified.
- The @MixinClasses annotation allows a set of mixin classes to be specified directly.
The former is often less verbose, and allows core mixins to be overridden with application-specific mixins. The later format is more specific and more refactor-safe (renaming a mixin class will rename the entry in the MixinClasses annotation as well).
Example:
Code Block | ||||
---|---|---|---|---|
| ||||
@Component(parameters=. . .) @Mixins({"Autocomplete", "DefaultFromCookie"}) private TextField userId; |
This example defines a component of type TextField and mixes in the hypothetical Autocomplete and DefaultFromCookie mixins.
Ordering the Mixins
With @Mixins and @MixinClasses annotations, we can order the list of mixins, by adding a constraint.
Code Block | ||||
---|---|---|---|---|
| ||||
@Component(parameters=. . .) @Mixins({"Autocomplete", "DefaultFromCookie::before:Autocomplete"}) private TextField userId; |
Code Block | ||||
---|---|---|---|---|
| ||||
@Component(parameters=. . .) @MixinClasses(value={Autocomplete.class, DefaultFromCookie.class}, order={"","before:AutoComplete"}) private TextField userId; |
You can specify many contraints for a mixin. You just need to separate them with a ";".
Implementation Mixins
Implementation mixins, mixins which apply to all instances of a component, are added using the @Mixin annotation. This annotation defines a field that will contain the mixin instance.
Code Block | ||||
---|---|---|---|---|
| ||||
public class AutocompleteField extends TextField { @Mixin private Autocomplete autocompleteMixin; . . . } |
Often, the type of the field is the exact mixin class to be instantiated.
In other cases, such as when the field's type is an interface or a base class, the value attribute of the annotation will be used to determine the mixin class name:
Code Block | ||||
---|---|---|---|---|
| ||||
public class AutocompleteField extends TextField { @Mixin("Autocomplete") private Object autocompleteMixin; . . . } |
Mixin Parameters
Mixins are allowed to have parameters, just like components.
When binding parameters (either in the template, or using the parameters attribute of the Component annotation), Tapestry will match each parameter name against the parameters defined by each class (which is to say, the component and each mixin).
If the component and a mixin both define a parameter with the same name, then the component wins: the component's parameter will be bound, and the mixin's parameter will be unbound.
Alternately, you may prefix the name of the parameter with the unqualified name of the Mixin class; this eliminates the ambiguity. Example:
Code Block | ||||
---|---|---|---|---|
| ||||
@Component(parameters={"Autocomplete.id=auto", . . . }) @Mixins("Autocomplete", "DefaultFromCookie"}) private TextField userId; |
Note that when you define an implementation mixin, and the mixin has parameters, there's no way to bind those parameters as part of the implementation. They simply become available when the composite component (including the mixin) is introduced into a page.
Render Phase Ordering
All mixins for a component execute their render phase methods before the component's render phase methods for most phases. However, in the later phases (AfterRender, CleanupRender) the order of executing is reversed.
Exception: A mixins whose class is annotated with @MixinAfter is ordered after the component, not before.
Available Mixins
Include Page | ||||
---|---|---|---|---|
|
In addition, the following mixins are available from other sources:
From JumpStart, a mixin to apply to a submit button, ensuring it can't be double-clicked | |
Adds a JavaScript confirm prompt to any link |
Additional Tools
Tapestry-Xpath is a third-part Tapestry module that allows XPath traversal of the Tapestry (server-side) DOM, which can be extremely useful in certain mixins.