Tapestry 5
  1. Tapestry 5
  2. TAP5-103

provide access to component parameters from within mixins

    Details

    • Type: New Feature New Feature
    • Status: Closed
    • Priority: Major Major
    • Resolution: Fixed
    • Affects Version/s: 5.0.15
    • Fix Version/s: 5.2.0
    • Component/s: None
    • Labels:
      None

      Description

      A mixin can't access the parameters of a component because the Bindings property of the InternalComponentResourcesImpl class is private and the respective interface does not provide a access method.

      I was trying to create a mixin that would render only the value of a form element (without the tags) when it was in a certain state. There also might be use cases where mixins are used to collect data from the components they are attached and therefore also needs access to the components parameters.

      see threads:
      http://www.nabble.com/Antwort%3A--T5--how-to-read-the-value-of-a-component-parameter-within-a-mixin-tf4487995.html
      http://www.nabble.com/-T5--how-to-read-the-value-of-a-component-parameter-within-a-mixin-tf4487597.html

        Activity

        Hide
        Nick Westgate added a comment -

        It would be nice if the core component library could be made more malleable in this way (and in general).
        With parameters etc declared private and no accessors it's very hard to modify their behaviour, e.g. with mixins.

        Cheers,
        Nick.

        Show
        Nick Westgate added a comment - It would be nice if the core component library could be made more malleable in this way (and in general). With parameters etc declared private and no accessors it's very hard to modify their behaviour, e.g. with mixins. Cheers, Nick.
        Hide
        Howard M. Lewis Ship added a comment -

        My concern here is that if the binding is used in multiple components (considering a mixin as a component), and yet cached in different variables of those components, it could easily end up with different values.

        Thus, the Form component evaluates its binding and stores a value in a local instance variable. The Magic mixin updates an instance variable and pushes the change through the binding. Now the Magic mixin has one value in an instance variable, the Form has another. Which one is right?

        Do we scrap the idea of local instance variables to store binding values? Well there's a lot of value in keeping that, such as limiting how many times a value has to be type coerced, and allowing for unbound parameters to still act like fields.

        So I think we need a solution where the instance variables of the Mixin are linked to the instance variables of the containing component through some additional mechanism I'm not sure of yet.

        Show
        Howard M. Lewis Ship added a comment - My concern here is that if the binding is used in multiple components (considering a mixin as a component), and yet cached in different variables of those components, it could easily end up with different values. Thus, the Form component evaluates its binding and stores a value in a local instance variable. The Magic mixin updates an instance variable and pushes the change through the binding. Now the Magic mixin has one value in an instance variable, the Form has another. Which one is right? Do we scrap the idea of local instance variables to store binding values? Well there's a lot of value in keeping that, such as limiting how many times a value has to be type coerced, and allowing for unbound parameters to still act like fields. So I think we need a solution where the instance variables of the Mixin are linked to the instance variables of the containing component through some additional mechanism I'm not sure of yet.
        Hide
        Kevin Menard added a comment -

        I meant to add in my two cents on this issue after raising a question about mixins on the user list. The key point from that was the following:

        "What I'm looking to do is is basically a value filter. I'd like the mixin
        to take the value, apply its filter, and pass on to the next mixin or
        component in the chain. I've actually got several other candidate
        operations in mind as well (truncation, capitalization, URLification)."

        In my case, I'm not actually looking to modify any bound values, so nothing would change behind the scenes – I agree that that's a situation looking to explode and would be incredibly frustrating to debug. What I want to do is intercept the supplied value from a mixin and then pass that value onto either the next mixin or component. A read-only access to the bound value would get us half-way there, but there are obvious problems with mutable state. While there are certainly a lot of problems that could arise there, enough sign posts have been placed by then that a mixin author really should know what he ought and ought not be doing.

        Show
        Kevin Menard added a comment - I meant to add in my two cents on this issue after raising a question about mixins on the user list. The key point from that was the following: "What I'm looking to do is is basically a value filter. I'd like the mixin to take the value, apply its filter, and pass on to the next mixin or component in the chain. I've actually got several other candidate operations in mind as well (truncation, capitalization, URLification)." In my case, I'm not actually looking to modify any bound values, so nothing would change behind the scenes – I agree that that's a situation looking to explode and would be incredibly frustrating to debug. What I want to do is intercept the supplied value from a mixin and then pass that value onto either the next mixin or component. A read-only access to the bound value would get us half-way there, but there are obvious problems with mutable state. While there are certainly a lot of problems that could arise there, enough sign posts have been placed by then that a mixin author really should know what he ought and ought not be doing.
        Hide
        Kevin Menard added a comment -

        Aforementioned thread: http://markmail.org/message/5gax6ms2tx5o3jbh

        For the time being, I've got a binding that does what I immediately need. I think letting mixins act as filters as described though could be a very powerful mechanism. I'm even envisioning a follow-up to expansions that would make use of this, like so:

        $

        {someVar|newlines:mode=para|capitalize|truncate:max=400}

        Obviously, another issue for another day and syntax subject to change. I'm just trying to further define what I'd like to do.

        Show
        Kevin Menard added a comment - Aforementioned thread: http://markmail.org/message/5gax6ms2tx5o3jbh For the time being, I've got a binding that does what I immediately need. I think letting mixins act as filters as described though could be a very powerful mechanism. I'm even envisioning a follow-up to expansions that would make use of this, like so: $ {someVar|newlines:mode=para|capitalize|truncate:max=400} Obviously, another issue for another day and syntax subject to change. I'm just trying to further define what I'd like to do.
        Hide
        Kristian Marinkovic added a comment -

        my original intend was to create mixins that could use the parameters of the component to decide further actions. a very concrete example is a EnableDisable mixin that
        would render only the value of a disabled TextField (i know there is a disabled parameter but if enabled it will still render the whole input element; applications with many input fields and high traffic will profit from the reduced page size).

        therefore i'd be more than satisfied to have an read-only access to the parameter binding from within a mixin. i'm aware that the value of the parameter could be changed by the component but that's ok with me because the rendering phases (after/before and MixinAfter) give you a hint on whether the value could have been changed by the component.

        for me mixins are a great way to add additional (maybe cross-cutting) behavior to a component regarding visual appearance and functionality on the client-side. I do not see mixins as a way to add business logic such as mentioned by kevin.... i think Validators and Translators are more suitable for this.

        Show
        Kristian Marinkovic added a comment - my original intend was to create mixins that could use the parameters of the component to decide further actions. a very concrete example is a EnableDisable mixin that would render only the value of a disabled TextField (i know there is a disabled parameter but if enabled it will still render the whole input element; applications with many input fields and high traffic will profit from the reduced page size). therefore i'd be more than satisfied to have an read-only access to the parameter binding from within a mixin. i'm aware that the value of the parameter could be changed by the component but that's ok with me because the rendering phases (after/before and MixinAfter) give you a hint on whether the value could have been changed by the component. for me mixins are a great way to add additional (maybe cross-cutting) behavior to a component regarding visual appearance and functionality on the client-side. I do not see mixins as a way to add business logic such as mentioned by kevin.... i think Validators and Translators are more suitable for this.
        Hide
        Robert Zeigler added a comment -

        I think Howard's idea of linking mixin parameters to component parameters sounds cool. Could this be done as a set of chained bindings? So, the page has a property "foo" bound to the component a's "value" parameter. Mixin B does something like:

        @InheritParameter
        private Object value;

        Now, the binding is altered so that:
        foo => mixinb.value => componenta.value

        So a change to componenta.value would propagate to mixinb.value and from there be pushed to to the page's foo property?

        This might break down with multiple mixins, unless you chained them all together, in the order that they're defined for the component, perhaps:

        foo => mixina.value => mixinb.value => mixinc.value => componentd.value

        Not sure how feasible this is.
        But this is definitely a crippling issue for mixins. Mixins have the potential to be really cool, but as they stand now, they're only sorta cool, because many of the more interesting things you would want to do with them require access to the underlying component's parameters.

        Show
        Robert Zeigler added a comment - I think Howard's idea of linking mixin parameters to component parameters sounds cool. Could this be done as a set of chained bindings? So, the page has a property "foo" bound to the component a's "value" parameter. Mixin B does something like: @InheritParameter private Object value; Now, the binding is altered so that: foo => mixinb.value => componenta.value So a change to componenta.value would propagate to mixinb.value and from there be pushed to to the page's foo property? This might break down with multiple mixins, unless you chained them all together, in the order that they're defined for the component, perhaps: foo => mixina.value => mixinb.value => mixinc.value => componentd.value Not sure how feasible this is. But this is definitely a crippling issue for mixins. Mixins have the potential to be really cool, but as they stand now, they're only sorta cool, because many of the more interesting things you would want to do with them require access to the underlying component's parameters.
        Hide
        Alfie Kirkpatrick added a comment -

        I have voted for this issue because I also think Howard's idea of somehow linking parameters together would be really elegant if achievable.

        But isn't there a simple workaround where we just duplicate the parameter between the mixin and the container? I have a zone parameter on my overlay mixin so if I mix it with another component that also has a zone parameter I need:

        <t:actionlink zone="zone1" overlay.zone="zone1">...</t:actionlink>

        In my case it is a literal but if it was a property binding, wouldn't changes to the property be propogated between the component and the mixin?

        Show
        Alfie Kirkpatrick added a comment - I have voted for this issue because I also think Howard's idea of somehow linking parameters together would be really elegant if achievable. But isn't there a simple workaround where we just duplicate the parameter between the mixin and the container? I have a zone parameter on my overlay mixin so if I mix it with another component that also has a zone parameter I need: <t:actionlink zone="zone1" overlay.zone="zone1">...</t:actionlink> In my case it is a literal but if it was a property binding, wouldn't changes to the property be propogated between the component and the mixin?
        Hide
        Robert Zeigler added a comment -

        That's only true if the user provides an explicit binding. Often, the user will rely on component-provided defaults, and a mixin may want to alter those defaults, or at least have clean access to the values.

        Show
        Robert Zeigler added a comment - That's only true if the user provides an explicit binding. Often, the user will rely on component-provided defaults, and a mixin may want to alter those defaults, or at least have clean access to the values.
        Hide
        Robert Zeigler added a comment -

        Howard's comment above about cached values was definitely the biggest challenge in implementing this. What I wound up doing was making the component and mixins "listen" for changes to the parameter value, and share the same binding. So if a mixin writes a value, that value is pushed back via write, and other mixins and the core component are notified via an internal event, coordinated by the ParameterAccess object for the component's parameter. As for "which value is right": they all wind up with the same value, and it's a matter of "last one to set the value is the winner". This is one of the pieces that really drove me to implement TAP5-777 (mixin ordering), as well, so that you can have deterministic behavior when you have multiple mixins (potentially) setting the same value.

        Show
        Robert Zeigler added a comment - Howard's comment above about cached values was definitely the biggest challenge in implementing this. What I wound up doing was making the component and mixins "listen" for changes to the parameter value, and share the same binding. So if a mixin writes a value, that value is pushed back via write, and other mixins and the core component are notified via an internal event, coordinated by the ParameterAccess object for the component's parameter. As for "which value is right": they all wind up with the same value, and it's a matter of "last one to set the value is the winner". This is one of the pieces that really drove me to implement TAP5-777 (mixin ordering), as well, so that you can have deterministic behavior when you have multiple mixins (potentially) setting the same value.

          People

          • Assignee:
            Robert Zeigler
            Reporter:
            Kristian Marinkovic
          • Votes:
            10 Vote for this issue
            Watchers:
            4 Start watching this issue

            Dates

            • Created:
              Updated:
              Resolved:

              Development