Create components dynamically and add to page

classic Classic list List threaded Threaded
3 messages Options
Reply | Threaded
Open this post in threaded view
|

Create components dynamically and add to page

Carlos Montero Canabal
Hi tapestry users,

I’m developing a configurable dashboard page where a user can select different widgets to his own dashboard. I’m thinking on save on database the widgets with his configuration per user. I would like to do something like this:

<t:loop source="widgets" value="widget">
        <t:delegate to=“createWidget”/>
</t:loop>  

And in my page class something like:

public Block getCreateWidget(){

        return componentSource.getComponent(widget.getComponentClassName()); <!-— This method “getComponent” by name/class doesn´t exists, only for logical page names —>
}

Where widget.getComponentClassName() returns, for example, "components/Widget1” or “my.package.components.Widget1".

Do you know if it’s possible this approach on Tapestry5?? With pages it works fine (I do it multiple times for email rendering), but with components I don’t found a method o service…

For other hand, I found a core component “Dynamic”. Is there any example of use?

Thank you everyone

Best regards

Carlos Montero

http://tapestry5.dev-util.com/ <http://tapestry5.dev-util.com/>


Reply | Threaded
Open this post in threaded view
|

Re: Create components dynamically and add to page

Thiago H de Paula Figueiredo
On Thu, Apr 12, 2018 at 1:52 PM, Carlos Montero Canabal <
[hidden email]> wrote:

> Hi tapestry users,
>

Hello!

Being pedantic and accurate, the subject line of your e-mail is incorrect:
Tapestry 5 doesn't support adding components dynamically to a page or
component. The structure of pages and components are strictly static. You
need to declare a component in a template in order to use it. There are no
exceptions.

On the other hand, you have all the freedom to run your templates in any
way you choose, with logic dictating what gets actually rendered.


> I’m developing a configurable dashboard page where a user can select
> different widgets to his own dashboard. I’m thinking on save on database
> the widgets with his configuration per user. I would like to do something
> like this:
>
> <t:loop source="widgets" value="widget">
>         <t:delegate to=“createWidget”/>
> </t:loop>
>
> And in my page class something like:
>
> public Block getCreateWidget(){
>
>         return componentSource.getComponent(widget.getComponentClassName());
> <!-— This method “getComponent” by name/class doesn´t exists, only for
> logical page names —>
> }
>
> Where widget.getComponentClassName() returns, for example,
> "components/Widget1” or “my.package.components.Widget1".
>
> Do you know if it’s possible this approach on Tapestry5?? With pages it
> works fine (I do it multiple times for email rendering), but with
> components I don’t found a method o service…
>

Using the Delegate component to dynamically choose which Block or component
instance to render is correct. On the other hand, the getCreateWidget()
method as described above won't work at all.

What actually works is declaring <t:block>s in a page, using
ComponentSource.getPage() to get an instance of that page, which is
returned as a Component instance, then calling
getComponentResources().getBlock(String id) to get the Block instance to
pass to the Delegate component. That's exactly how the BeanModel-based
components, such as Grid, BeanEditor, BeanDisplay and BeanEditForm work.


> Thank you everyone
>
> Best regards
>
> Carlos Montero
>
> http://tapestry5.dev-util.com/ <http://tapestry5.dev-util.com/>
>
>
>


--
Thiago
Reply | Threaded
Open this post in threaded view
|

Re: Create components dynamically and add to page

Carlos Montero Canabal
Hi Thiago,

Thank you for your reply.

Yes, I know that the correct subject would be “adding components dynamically to a page” and not the “create” term. I develop the solution bellow that works fine for me:

<div class="row">
           
        <t:loop source="widgets" value="widget">
                               
                <t:delegate to="dynamicWidget"/>
                               
        </t:loop>            
           
        <t:block t:id="widgetsDefinition">
           
            <t:widgets.widgetTest1 t:id="widget1" />
           
            <t:widgets.widgetTest2 t:id="widget2" />
           
        </t:block>
           
</div>

And my .java:

public Object getDynamicWidget(){
                WidgetFacade widgetFacade = (WidgetFacade) componentSource.getComponent("Index:" + widget.getWidget().getComponentId());
                Map<String, String> configuration = new HashMap<String, String>();
                for(WidgetConfiguration conf : widget.getConfigurations()){
                        configuration.put(conf.getConfigurationKey(), conf.getConfigurationValue());
                }
                widgetFacade.init(configuration);
                return widgetFacade;
}

I wanted to skip the block “widgetsDefinition” but it’s not possible.

Thank you

Best regards

Carlos Montero

> El 12/4/2018, a las 21:55, Thiago H. de Paula Figueiredo <[hidden email]> escribió:
>
> On Thu, Apr 12, 2018 at 1:52 PM, Carlos Montero Canabal <
> [hidden email]> wrote:
>
>> Hi tapestry users,
>>
>
> Hello!
>
> Being pedantic and accurate, the subject line of your e-mail is incorrect:
> Tapestry 5 doesn't support adding components dynamically to a page or
> component. The structure of pages and components are strictly static. You
> need to declare a component in a template in order to use it. There are no
> exceptions.
>
> On the other hand, you have all the freedom to run your templates in any
> way you choose, with logic dictating what gets actually rendered.
>
>
>> I’m developing a configurable dashboard page where a user can select
>> different widgets to his own dashboard. I’m thinking on save on database
>> the widgets with his configuration per user. I would like to do something
>> like this:
>>
>> <t:loop source="widgets" value="widget">
>>        <t:delegate to=“createWidget”/>
>> </t:loop>
>>
>> And in my page class something like:
>>
>> public Block getCreateWidget(){
>>
>>        return componentSource.getComponent(widget.getComponentClassName());
>> <!-— This method “getComponent” by name/class doesn´t exists, only for
>> logical page names —>
>> }
>>
>> Where widget.getComponentClassName() returns, for example,
>> "components/Widget1” or “my.package.components.Widget1".
>>
>> Do you know if it’s possible this approach on Tapestry5?? With pages it
>> works fine (I do it multiple times for email rendering), but with
>> components I don’t found a method o service…
>>
>
> Using the Delegate component to dynamically choose which Block or component
> instance to render is correct. On the other hand, the getCreateWidget()
> method as described above won't work at all.
>
> What actually works is declaring <t:block>s in a page, using
> ComponentSource.getPage() to get an instance of that page, which is
> returned as a Component instance, then calling
> getComponentResources().getBlock(String id) to get the Block instance to
> pass to the Delegate component. That's exactly how the BeanModel-based
> components, such as Grid, BeanEditor, BeanDisplay and BeanEditForm work.
>
>
>> Thank you everyone
>>
>> Best regards
>>
>> Carlos Montero
>>
>> http://tapestry5.dev-util.com/ <http://tapestry5.dev-util.com/>
>>
>>
>>
>
>
> --
> Thiago