You are viewing a plain text version of this content. The canonical link for it is here.
Posted to users@myfaces.apache.org by simon <si...@chello.at> on 2007/12/17 09:59:01 UTC

Re: Adding a property to a component and rendering it ... the magic way?

Hi Ole,

It is good to know that Facelets adds attributes automatically.

Yes, I guess it would be possible to modify
  HtmlRendererUtils.renderHtmlAttributes
to also look into the component it is passed for extra attributes that
it should write. It does mean retrieving the FacesContext from the
current thread and using that to get the configuration data (the names
of "magic" attributes) but that doesn't seem too evil to me.

But a ResponseWriter-based approach can do very much the same thing.

The advantage of doing it in HtmlRenderUtils is that it should work
better for components that output multiple HTML tags. In this case, the
renderer would normally invoke this method only for the "main" element.

However the advantage of doing it in ResponseWriter is that it will work
for all JSF components, not just the MyFaces ones. I think that is
extremely useful..

Regards,

Simon

On Mon, 2007-12-17 at 00:22 -0600, Ole Ersoy wrote:
> Good News - The tag attributes are automatically added to the UIComponent.attributes map (At least they are by facelets).  That means it's possible to skip adding <f:attribute> tags.
> 
> WRT the responseWriter feature, I think it would be sweet if we could configure valid pass through attribute keys.  So for example:
> 
> <application>
>     <passthroughAttributes>
> 	<attribute name="comingOnThroughBeibe"/>
>     </passthroughAttributes>
> </application>
> 
> Then if the responseWriter saw the "comingOnThroughBeibe" key on one of the UIComponent.getAttributes() entries it would render it.
> 
> I think that would have to be implemented on the HtmlRenderer utility methods though (Moving away from the custom response writer idea a bit)?  A custom utility method would be used by the renderer developer to pass through attributes that are "Hard Coded" for pass through, as is currently done with the HTML constants, + any configured pass through attributes.
> 
> Thoughts?
> 
> Cheers,
> - Ole
> 
> 
> 
> 
> simon wrote:
> > Hmm..interesting suggestion, Andrew.
> > 
> > So a custom responsewriter could potentially be written to allow the
> > insertion of new attributes onto the html tag for any component?
> > 
> > Is this what you were thinking of?
> > 
> > startElement(String ename, UIComponent component) {
> >    // start xml element
> >    // if (component not in already-processed list)
> >    //   for each key in component.getAttributes()
> >    //     if key.startsWith("tunnelledAttribute:")
> >    //       output (key, value) as xml attributes
> >    // store component in already-processed list
> > }
> > 
> > Then:
> >   <h:someTag ..>
> >     <f:attribute name="tunnelledAttribute:foo" value="bar"/>
> > 
> > That might be interesting to add to the standard MyFaces
> > ResponseWriter...
> > 
> > Regards,
> > 
> > Simon
> > 
> > On Fri, 2007-12-14 at 19:54 -0700, Andrew Robinson wrote:
> >> Most renderers will not give you access to the root element to be able
> >> to add attributes. However, if the renderers are correctly using the
> >> response writer, they should be calling startElement(String,
> >> UIComponent). By subclassing this, you can trap the call, look for you
> >> attributes and add them to the element.
> >>
> >> -Andrew
> >>
> >> On Dec 14, 2007 7:07 PM, Ole Ersoy <ol...@gmail.com> wrote:
> >>> Hi,
> >>>
> >>> I have a attribute that I just need to get passed through to the corresponding html element.  For example:
> >>>
> >>> <h:form id="registrationForm"
> >>>         anAdditionalAttribute="I need to get through to the form element">
> >>> </h:form>
> >>>
> >>>
> >>> In the rendered output I would like:
> >>>
> >>> <form
> >>>         ...
> >>>         anAdditionalAttribute="I need to get through to the form element">
> >>> </form>
> >>>
> >>>
> >>> I think the process for doing this (Excluding component registration, etc.) is first to subclass the form component and add the "anAdditionalAttribute" to the subclass.  Then subclass the corresponding renderer and render this attribute.
> >>>
> >>> Does anyone know if there's a quicker/magic way to get the job done?
> >>>
> >>> Thanks,
> >>> - Ole
> >>>
> >>>
> >>>
> > 
> > 


Re: Adding a property to a component and rendering it ... the magic way?

Posted by Ole Ersoy <ol...@gmail.com>.
Hi Simon,

simon wrote:
> Hi Ole,
> 
> It is good to know that Facelets adds attributes automatically.

Yes it's great.  Kudos to Jacob!

> 
> Yes, I guess it would be possible to modify
>   HtmlRendererUtils.renderHtmlAttributes
> to also look into the component it is passed for extra attributes that
> it should write. It does mean retrieving the FacesContext from the
> current thread and using that to get the configuration data (the names
> of "magic" attributes) but that doesn't seem too evil to me.
> 
> But a ResponseWriter-based approach can do very much the same thing.

Would that work sort of like this (99% your and Andrew's material I think):

//responseWriter.startFormElement...
//write the normal form attributes
//call responseWriter.writeAdditionalAttributes()
//close starting Element

And I think you indicated that the response writer would know how to write the the additional attribute because it would have a namespace prefix like "additionalAttribute:".  I guess this prefix could be made configurable?  Also what if the whole attribute name was configurable.  So if the attribute entry was keyed with name "ajaxComponent"...then send it through.

> 
> The advantage of doing it in HtmlRenderUtils is that it should work
> better for components that output multiple HTML tags. In this case, the
> renderer would normally invoke this method only for the "main" element.
> 
If I understand correctly, it now seems that the HtmlRendererUtils is fine doing what it's doing currently, and that the renderers should just do a responseWriter.writeAdditionalAttributes() inside encodeBegin, which would take care of this "Developer Use Case" entirely.

> However the advantage of doing it in ResponseWriter is that it will work
> for all JSF components, not just the MyFaces ones. I think that is
> extremely useful..

Indeed.  I'd like to give this a shot and would be delighted if it became part of the core or if it became useful in general...assuming I get it?

I think the task plan would be something like this:

- Understand how to configure a new ResponseWriter for JSF (We need to plugin a new one right?)
- Subclass the existing response writer
- Add the renderAdditionalAttributes() method.
- Figure out where the ResponseWriter gets it's configuration from...web.xml?
- Pass the necessary configuration so that renderAdditionalAttributes() has access.

And the rest is pretty easy I think...

Thanks again for the "Brain Jumping",
- Ole

Re: Adding a property to a component and rendering it ... the magic way?

Posted by Ole Ersoy <ol...@gmail.com>.
Hey Simon,

You're a saint.  Bet you never heard that before.  Thanks you so much (Martin and Andrew as well) for all the help.  I did this:

svn co http://svn.apache.org/repos/asf/myfaces/core/branches/1_2_0 myfaces_core_1.2.0
svn co http://svn.apache.org/repos/asf/myfaces/shared/branches/3_0_0 myfaces_shared_3.0.0

Added my passthrough attributes to COMMON_PASSTHROUGH_ATTRIBUTES on the HTML constants.

Rebuilt shared then core, and now the additional attributes are coming through as expected.  This takes care of my requirements, but I'd still be happy to collaborate on getting the response writer gig working.  I could also send a note about it out on the developer list if you think it's a good idea.

Thanks again,
- Ole



simon wrote:
> Hi Ole,
> 
> It is good to know that Facelets adds attributes automatically.
> 
> Yes, I guess it would be possible to modify
>   HtmlRendererUtils.renderHtmlAttributes
> to also look into the component it is passed for extra attributes that
> it should write. It does mean retrieving the FacesContext from the
> current thread and using that to get the configuration data (the names
> of "magic" attributes) but that doesn't seem too evil to me.
> 
> But a ResponseWriter-based approach can do very much the same thing.
> 
> The advantage of doing it in HtmlRenderUtils is that it should work
> better for components that output multiple HTML tags. In this case, the
> renderer would normally invoke this method only for the "main" element.
> 
> However the advantage of doing it in ResponseWriter is that it will work
> for all JSF components, not just the MyFaces ones. I think that is
> extremely useful..
> 
> Regards,
> 
> Simon
> 
> On Mon, 2007-12-17 at 00:22 -0600, Ole Ersoy wrote:
>> Good News - The tag attributes are automatically added to the UIComponent.attributes map (At least they are by facelets).  That means it's possible to skip adding <f:attribute> tags.
>>
>> WRT the responseWriter feature, I think it would be sweet if we could configure valid pass through attribute keys.  So for example:
>>
>> <application>
>>     <passthroughAttributes>
>> 	<attribute name="comingOnThroughBeibe"/>
>>     </passthroughAttributes>
>> </application>
>>
>> Then if the responseWriter saw the "comingOnThroughBeibe" key on one of the UIComponent.getAttributes() entries it would render it.
>>
>> I think that would have to be implemented on the HtmlRenderer utility methods though (Moving away from the custom response writer idea a bit)?  A custom utility method would be used by the renderer developer to pass through attributes that are "Hard Coded" for pass through, as is currently done with the HTML constants, + any configured pass through attributes.
>>
>> Thoughts?
>>
>> Cheers,
>> - Ole
>>
>>
>>
>>
>> simon wrote:
>>> Hmm..interesting suggestion, Andrew.
>>>
>>> So a custom responsewriter could potentially be written to allow the
>>> insertion of new attributes onto the html tag for any component?
>>>
>>> Is this what you were thinking of?
>>>
>>> startElement(String ename, UIComponent component) {
>>>    // start xml element
>>>    // if (component not in already-processed list)
>>>    //   for each key in component.getAttributes()
>>>    //     if key.startsWith("tunnelledAttribute:")
>>>    //       output (key, value) as xml attributes
>>>    // store component in already-processed list
>>> }
>>>
>>> Then:
>>>   <h:someTag ..>
>>>     <f:attribute name="tunnelledAttribute:foo" value="bar"/>
>>>
>>> That might be interesting to add to the standard MyFaces
>>> ResponseWriter...
>>>
>>> Regards,
>>>
>>> Simon
>>>
>>> On Fri, 2007-12-14 at 19:54 -0700, Andrew Robinson wrote:
>>>> Most renderers will not give you access to the root element to be able
>>>> to add attributes. However, if the renderers are correctly using the
>>>> response writer, they should be calling startElement(String,
>>>> UIComponent). By subclassing this, you can trap the call, look for you
>>>> attributes and add them to the element.
>>>>
>>>> -Andrew
>>>>
>>>> On Dec 14, 2007 7:07 PM, Ole Ersoy <ol...@gmail.com> wrote:
>>>>> Hi,
>>>>>
>>>>> I have a attribute that I just need to get passed through to the corresponding html element.  For example:
>>>>>
>>>>> <h:form id="registrationForm"
>>>>>         anAdditionalAttribute="I need to get through to the form element">
>>>>> </h:form>
>>>>>
>>>>>
>>>>> In the rendered output I would like:
>>>>>
>>>>> <form
>>>>>         ...
>>>>>         anAdditionalAttribute="I need to get through to the form element">
>>>>> </form>
>>>>>
>>>>>
>>>>> I think the process for doing this (Excluding component registration, etc.) is first to subclass the form component and add the "anAdditionalAttribute" to the subclass.  Then subclass the corresponding renderer and render this attribute.
>>>>>
>>>>> Does anyone know if there's a quicker/magic way to get the job done?
>>>>>
>>>>> Thanks,
>>>>> - Ole
>>>>>
>>>>>
>>>>>
>>>
> 
>