I'm learning tapestry 5 web framework but I don't understand the principle 1 about it:
"Static Structure, Dynamic Behaviour", what does means it ?
If I don't add components to the components, how can I create a dynamic page?
anyone can help me?
Thanks in advance
It means that you can't choose or replace components at runtime effectively.
If, say, you'd want to build a portal solution where users could arrange components on a screen any way they wanted, Tapestry would not offer an effective way to do that, because components have static structure, i.e. you must define what goes into them at compile-time in their template file.
Or you might have a specialized menu for administrators, so you might want to just replace the Menu component with a derived component, AdminMenu - but you can't, you have to use if statements in the template or use a block to inject different menus into your layout component.
There's an anti-pattern related to this limitation: The God or über-component tries to solve this problem by effectively having a giant template file with all the available components, like this:
<t:if t:test="displayComponentA">
<span t:type="ComponentA" ... />
</t:if>
<t:if t:test="displayComponentB">
<span t:type="ComponentB" ... />
</t:if>
...
This, however, is horribly ineffective, as Tapestry assembles the entire component tree, including components that are not displayed, to do the rendering of the page.
Tapestry uses templates to define static content. These templates are usually html pages with placeholder variables which are replaced by some code dynamically by the framework. Templates allow for segregation of things that not change from the ones that change. Usually structure is less prone to change then behavior. Even if you want to change some element of a component dynamically you're going to use some component that itself is defined by a template that is dynamically filled with data. This dynamic data again can insert some other component etc.
Static structure doesn't mean that you cannot output dynamic content nor that you cannot add components to components. You just cannot add a component to another at runtime. You can define a page or component structure using other components, but this is all defined in the template, before the page is rendered, never while it's rendered. A component can choose not to render itself, to render part of its template (If and Unless components), etc.
One of the few practical situations caused by the static structure of Tapestry is that a component C cannot use another instance of the same component inside it.
Related
In a Magnolia/Blossom component, is it possible to define and render a child component of another type (or an Area that is defined to always contain exactly one component of a specific type, is prepopulated and has a clean author interface)?
e.g. I have a rich text component. I want to build another component that has an section within it that uses this rich text component. I could create an Area that has a maximum of 1 child components, and only allows this component type, but that would require the author to manually add it each time - plus the author interface is ugly*.
FWIW I'm using Magnolia 5.4.9, the Blossom module 3.1.3 and Thymeleaf 2.1.4.
*I have the following but this is what I'm trying to avoid - it contains 2 wrappers for a single component, plus a redundant 'maximum number of components reached' area
To avoid having editor to create instance of the component manually, you can use autogeneration.
To get rid of green bars in UI ... apart from writing all yourself inside of single component, you can try to examine element IDs to see if you can custom tweak CSS to hide it, but like it will not be possible.
I'm working on a web project which uses JSF 2.0, PrimeFaces and PrettyFaces as main frameworks / libraries. The pages have the following (common) structure: Header, Content, Footer.
Header:
The Header always contains the same menu. This menu is a custom component, which generates a recursive html <ul><li> list containing <a href="url"> html links, this is all rendered with a custom renderer. The link looks like 'domain.com/website/datatable.xhtml?ref=2'. Where the ref=2 used to load the correct content from the database. I use prettyfaces to store this request value in a backingbean.
Question 1: Is it ok to render the <a href> links myself, or should I better add an HTMLCommandLink from my UIComponent and render that in the encodeBegin/End?
Question 2: I think passing variables like this is not really the JSF 2.0 style, how to do this in a better way?
Content:
The content contains dynamic data. It can be a (primefaces) datatable, build with dynamic data from the database. It can also be a text page, also loaded from the database. Or a series of graphs. You got the point, it's dynamic. The content is based on the link pressed in the header menu. If the content is of type datatable, then I put the ref=2 variable to a DataTableBean (via prettyfaces), which then loads the correct datatable from the database. If the content is of type chart, I'll put it on the ChartBean.
Question 3: Is this a normal setup? Ideally I would like to update my content via Ajax.
I hope it's clear :)
It's ok to just output link yourself, commandLink is out of the question (it does a postback using javascript, it's not what you want);
Parameter are all in the param implicit object. You can insert them by a #ManagedProperty annotation, like this:
#ManagedProperty("#{param.ref}")
String ref
// .. getters, setters (obligatory!)
You can also use (if you are on JSF 2) the f:viewParam tag (a nice description http://blogs.oracle.com/rlubke/entry/jsf_2_0_bookmarability_view), you get the bonus of validation and conversion.
The way I understand it, your setup is rather complicated. Using a handwritten custom component for a menu is a huge overkill (at least judging from the provided description), a composite component would probably do. JSF has no special way of making ajax calls between views or embedding views one into another, so - unless you use iframes - your only choice would be to include all the possible pieces of content into a single view, wrapped in panels, and render them as required:
<h:panelGroup rendered='#{backingBean.ref == 2}'>
... content 2 ...
</h:panelGroup>
and so on. Careful, this would be heavy on resources.
You could also write your own ajax solution in javascript. This would require all the pieces of content to be fully independent views, with their own forms. Also, all their postbacks would have to go through ajax, so the main page does not get reloaded.
I'm using a rich:simpleTogglePanel and it puts these 3 css classes on the divs:
rich-stglpanel
rich-stglpanel-header
rich-stglpnl-marker
rich-stglpanel-body
Is there any way that I can remove those classes?
Every Richfaces component comes with a set of CSS classes. These CSS classes are used to customize the aspect of your toggle panel (or any other RF component). The four CSS classes, as explained in the component guide, are indeed attached to the HTML components generated by the RF framework.
There are 2 solutions for you:
Customize your CSS in order to extend the default properties of the four CSS classes. This way, you will have the rendering you want for this component.
Remove the CSS classes using JavaScript (not recommanded).
The second solution can be achieved easily with some jQuery script:
jQuery(document).ready(function() {
jQuery(".rich-stglpanel").removeClass("rich-stglpanel");
...
});
(this means once the page is loaded, find all elements with CSS class rich-stglpanel and remove this class).
I'm having a problem when trying to use layouts in the Play! Framework. As far as I know, a layout has a SINGLE #{doLayout /} tag that specifies where all the code of the child view should be placed. This means that all the code in a particular view of, say, list of Users (list.html) gets injected in the middle of the body of the layout. Now, I find that some of my views require javascript that is particular to those views, and so I'd like to include script tags only on those views and not on every single view that inherits from the layout. The Razor view engine in ASP.NET MVC allows for different sections in a layout that are filled in by a view that extends that layout, but I don't know if Play supports something like this.
Do you see a solution to this problem?
You can also use the #get,#set tags to define other blocks. For example:
#{set 'anyBlock'}
<h1>Main title</h1>
#{/set}
and:
#{get 'anyBlock' /}
You can use the script tag in your specific views. For instance :
#{script 'jquery.js' /}
I recommend you to read this documentation page :
http://www.playframework.org/documentation/1.1/tags#script
I have a question about GUI design, specifically with Java Swing and creating clean separation between presentation and model.
It's a bit difficult to describe, but essentially we have lots of reference data in our system (i.e. that would correspond to lookup tables in the DB). We want people to be able to edit them all from one screen.
So, in an ideal world what we'd like is a combo box in the top-left corner with a list of 'types' of reference data (so each corresponding to one table in the DB).
Then, when selected, a list of the data is populated below, also a filter (or search box). When one of these items is selected, the panel to the right is activated which will allow the actual data to be edited.
Now, here's the problem: each type of data we need to edit is different, so it has different fields etc. We could go with a generic solution but I'm not really a fan of them - there are lots of different validation rules for each etc, even for different clients, and it would be a nightmare to manage.
We're using the Presentation Model pattern to achieve some degree of separation between GUI code and the model but I can't think of a clean way of doing this which doesn't somehow blur the line of responsibilities a bit.
What are the ways you have solved problems like this?
[Note: apologies for the long question, hope it's understandable, I can re-phrase if necessary]
You could use the Factory Pattern to create a UI widget for the element that you are selecting. You could also use it to create a validation rule object depending on the type. This would give you some of the flexibility you desire.
So you can have something like:
IWidget widget = UIFactory.createFor(myObject.getType())
That can be invoked on the selection event to create the right widget to edit the selected element.
The IWidget could have methods such as:
validateData()
refreshData()
setDataElement(IDataElement element)
That would allow you to treat all UI widgets generically, but still have a special UI widget for each element type. I am assuming that the elements that you are selecting from the table all implement some IDataElement interface that contains the getType() method.
I used this solution tied together with the Eclipse Extension mechanism to plug-in new UI elements into my "base" solution, to have an extensible core and a high level of reuse. You could achieve something similar by injecting types and widgets into your factory, either manually or with Spring.
If you dont want to go down the generic path, you could have your model hold a mapping of combobox item -> panel name for use with a CardLayout. You could then create custom panels for the editing each of the reference data types. When the combo box selection is changed, you can save the current state in your model, request the panel name of the current selection, prepare your next panel for display and then have your CardLayout show it.