Dear Wiki user, You have subscribed to a wiki page or wiki category on "Tapestry Wiki" for change notification.
The following page has been changed by FilipSAdamsen: http://wiki.apache.org/tapestry/Tapestry5HowToAddBindingPrefix The comment on the change is: Updated text, examples, and code. ------------------------------------------------------------------------------ - In this example we will create our own binding prefix to support array/list values directly in template without needing to write a getter method.[[BR]] + In this example we will create a list binding prefix to support array/list values directly in templates without needing to write getter methods.[[BR]] - This is tested on (5.0.5), it will most likely be a part of the framework in some way, but currently it isn't, and to show how easy it is to extend tapestry....[[BR]] + This is tested on Tapestry 5.0.14, it will most likely be a part of the framework in some way, but currently it isn't.[[BR]] - For example if you want to link your product page, you will write this in tempalte : + Example: You have a product page, product/view, and you want to be able to compare the current product to a list of related products. So you write this in your template: {{{ - <T:ActionLink page="Product" context="producViewLink">View</T:ActionLink> - <T:ActionLink page="Product" context="producEditLink">Edit</T:ActionLink> + <t:loop t:source="relatedproducts" t:value="relatedproduct"> + <t:pagelink page="product/compare" context="productcomparecontext">Compare with ${relatedproduct.name}</t:pagelink> + </t:loop> }}} - and this in your java class + And this in your Java class: {{{ - public Object[] getProductViewLink(){ + public Object[] getProductCompareContext(){ - return new Object[]{product.getId(),"view"}; - } - public Object[] getProductEditLink(){ - return new Object[]{product.getId(),"edit"}; + return new Object[]{ product.getId(), relatedProduct.getId() }; } }}} - After following this example, the java part will not be needed and template will look something like this: + The list binding prefix simplifies this to: {{{ - <T:ActionLink page="Product" context="list:product.id,'view'">View</T:ActionLink> - <T:ActionLink page="Product" context="list:product.id,'edit'">Edit</T:ActionLink> + <t:loop t:source="relatedproducts" t:value="relatedproduct"> + <t:pagelink page="product/compare" context="list:product.id,relatedproduct.id">Compare with ${relatedproduct.name}</t:pagelink> + </t:loop> }}} + Let's implement the list binding prefix. - '''Now the example.''' - - Add this to your !AppModule.java + Add this to your !AppModule.java: {{{ public static void contributeBindingSource( MappedConfiguration<String, BindingFactory> configuration, BindingSource bindingSource) { - configuration.add("list",new ListBindingFactory(bindingSource)); + configuration.add("list", new ListBindingFactory(bindingSource)); } }}} - The !ListBindingFactory + The !ListBindingFactory: {{{ /** + * Factory for list bindings. List bindings parse comma-delimited lists of binding expressions into [EMAIL PROTECTED] List lists} + * of values. The default binding prefix for each binding expression is prop. - * Implementation of the list: binding prefix -- we parse list of bindings - * and generate delegate bindings for each element<br> - * default binding is prop, except when surrounded with '' or is a numeric value ([0-9.]*) */ public class ListBindingFactory implements BindingFactory { - private final BindingSource _bindingSource; + private final BindingSource bindingSource; + - public ListBindingFactory(BindingSource source){ + public ListBindingFactory(BindingSource source) { - this._bindingSource = source; + this.bindingSource = source; + } + + public Binding newBinding(String description, ComponentResources container, ComponentResources component, + String expression, Location location) { + List<Binding> delegates = new ArrayList<Binding>(); + String[] items = expression.split(","); + boolean invariant = true; + + for (String item : items) { + Binding binding = bindingSource.newBinding(description, container, component, + BindingConstants.PROP, item, location); + invariant = invariant && binding.isInvariant(); + delegates.add(binding); } - - public Binding newBinding(String description, ComponentResources container, ComponentResources component, - String expression, Location location) - { - List<Binding> delegates = new ArrayList<Binding>(); - String[] bindingNames = expression.split(","); - boolean isInvariant=true; - - for (String bindingName : bindingNames){ - String defaultBinding = TapestryConstants.LITERAL_BINDING_PREFIX; - - if(bindingName.charAt(0) == '\''){ - //translate "'something'" to "literal:something" - bindingName = bindingName.substring(1,bindingName.length()-1); - }else{ - //if value is numeric, we leave literal binding prefix as default - for (int i = 0; i < bindingName.length(); i++) { - char ch = bindingName.charAt(i); - if(ch != '.' && !Character.isDigit(ch)){ - defaultBinding = TapestryConstants.PROP_BINDING_PREFIX; - break; - } - } - } - - Binding binding = _bindingSource.newBinding(description, container, component, defaultBinding, bindingName, location); - isInvariant = isInvariant && binding.isInvariant(); - delegates.add(binding); - } - - return new ListBinding(delegates, isInvariant); + return new ListBinding(delegates, invariant); - } + } } }}} - The !ListBinding + The !ListBinding : {{{ - public class ListBinding extends AbstractBinding{ + public class ListBinding extends AbstractBinding { - private final List<Binding> delegates; - private final boolean _invariant; + private final List<Binding> delegates; + private final boolean invariant; + - public ListBinding(List<Binding> delegates, boolean invariant) { + public ListBinding(List<Binding> delegates, boolean invariant) { - this.delegates = delegates; + this.delegates = delegates; - _invariant = invariant; + this.invariant = invariant; + } + + public Object get() { + List<Object> values = new ArrayList<Object>(delegates.size()); + + for (Binding binding : delegates) { + values.add(binding.get()); } - public Object get() { - Object[] valuesFromDelegates = new Object[delegates.size()]; + return values; + } - for (int i = 0; i < delegates.size(); i++) { - valuesFromDelegates[i] = delegates.get(i).get(); - } - - return valuesFromDelegates; - } - - @Override - public boolean isInvariant() { + public boolean isInvariant() { - return _invariant; + return invariant; - } + } + - - @Override - public Class<Object[]> getBindingType() { + public Class<List> getBindingType() { - return Object[].class; + return List.class; - } + } } }}} - !Notice: although we named this binding "list" the value returned is an Object array, but tapestry will easily convert between the two. If you like, you can easily change this to return "List"[[BR]] - !Notice#2: you must override isInvariant and "return false" to avoid value being cached (in this example we return true if all sub expressions are invariant) + Notice: You must override isInvariant and return false to avoid the value being cached. In this example we return true if all binding expressions are invariant. - And that's it, you now have your own binding prefix. It splits the expression on "," and each subexpression will be evaluated as it was single binding expression (with exception for numeric values and values surrounded with ' ', which are prefixed literal). + And that's it. You now have a list binding prefix. It splits the expression on "," and each subexpression will be evaluated as it was a single binding expression. - for example a chart link (similar to chart example on this wiki) + For example a chart link - similar to the chart example (["Tapestry5HowToCreateASimpleGraphComponent"]) on this wiki - can be used like this with the list binding prefix: {{{ <t:chart width="200" height="150" context="list:'aa',22,'bb',5" popup="popupSize"/> <t:chart width="200" height="150" context="list:'aa',29,'bb',30,'cc',10" popup="popupSize"/> --------------------------------------------------------------------- To unsubscribe, e-mail: [EMAIL PROTECTED] For additional commands, e-mail: [EMAIL PROTECTED]
