Question

I have been trying to create a custom textfield in tapestry which will render some javascript when it gains focus. But I have been having trouble trying to find an example of this.

Here is some of the code i have started off with:

package asc.components;

import org.apache.tapestry5.ComponentResources;
import org.apache.tapestry5.Field;
import org.apache.tapestry5.annotations.Parameter;
import org.apache.tapestry5.ioc.annotations.Inject;
import org.apache.tapestry5.services.ComponentDefaultProvider;


public class DahserTextField implements Field {

@Parameter (defaultPrefix = "literal")
private String label;
@Inject
private ComponentResources resources;
@Inject
private ComponentDefaultProvider defaultProvider;
@Parameter
private boolean disabled;
@Parameter
private boolean required;

String defaultLabel(){
    return defaultProvider.defaultLabel(resources);
}

public String getControlName() {
    return null;
}

public String getLabel() {
    return label;
}

public boolean isDisabled() {
    return disabled;
}

public boolean isRequired() {
    return required;
}

public String getClientId() {
    return resources.getId();
}


}

I have been unsure on what to do next. I do not know what to put into the .tml file. I would be grateful if anyone could help or point me in the right direction.

Was it helpful?

Solution

There is no need to replicate any of TextField's functionality in your own component, instead you should create a component mixin. Mixins are designed to add behaviour to existing components.

From the Tapestry 5 docs:

Tapestry 5 includes a radical feature, component mixins. Component mixins are a tricky concept; it basically allows a true component to be mixed together with special limited components called mixins. The component plus its mixins are represented as just a single tag in the component template, but all the behavior of all the elements.

You would use the mixin like this:

<input type="text" t:type="TextField" t:mixins="MyMixin" t:someParam="foo" />

A mixin stub:

@IncludeJavaScriptLibrary("MyMixin.js")
public class MyMixin {

    /**
     * Some string param.
     */
    @Parameter(required = true, defaultPrefix = BindingConstants.LITERAL)
    private String someParam;

    @Environmental
    private RenderSupport renderSupport;

    @InjectContainer
    private AbstractTextField field;

    @AfterRender
    void addScript() {
        this.renderSupport.addScript("new MyJavascriptClass('%s', '%s');", 
                this.field.getClientId(), this.someParam);
    }

}

Note the @InjectContainer annotation, which injects the containing TextField into your Mixin. In this case, we want the TextField's clientId.

Also note the @IncludeJavaScriptLibrary("MyMixin.js") annotation, which includes the required Javascript file.

The Javascript could look like this:

MyJavascriptClass = Class.create({

    initialize: function(textField, someParam) 
    {
        this.textField = $(textField);
        this.someParam = someParam;

        this.textField.observe('focus', this.onFocus.bindAsEventListener(this));
    },

    onFocus: function(event)
    {
        //do something
    }
}

The key difference to your approach is that this involves defining your own JS class and using Tapestry's built-in facilities to load and initialize the JS. The use of mixins is also relatively light-weight and elegant in comparison to creating your own components.

OTHER TIPS

The .tml

<t:textfield onfocus="somethingCool()" />

The Java should probably extent TextField? It will need to import a new stylesheet too probably.

-- Pages are actually components, so you would build a component just like you would have any other page. You can embed any other component into them. I hope this is a good starting point for you.

Licensed under: CC-BY-SA with attribution
Not affiliated with StackOverflow
scroll top