So thanks to Timothy, I've been able to see some results with building a composite component. I tried using a dataTable method, but the UI was always a table visually which I did not want. My component is a simple panel with a + button to add multiple rows, each row would be an email, or in another component, an address form. Next to each added row(s) is a - button to delete that one.
So I got the + working where it adds a new item to my @ViewScoped bean, using a List<Email> for example as the backing model object. Using a ui:repeat, I am able to loop through all the List<Email> and display them. The + button adds another as I said and the refresh only redraws the newly added fields.
The problem I am trying to figure out right now is how to have each of the - buttons provide the specific email object in the List<Email> data model in my bean, so that I can remove the correct Email object. Not sure if I need to add some more EL in some way to specify the specific index within the List<Email> object looped in the ui:repeat, or something else? I am using the actionListener on the <h:commandButton> for the button so that I get the ActiionEvent in my method and can use that if that works?
Another thing I am not sure about.. in my case my component should be reusable. I've added a configurable List parameter, and use it in the ui:repeat to loop through and such. But it's possible a developer uses more than one of this component (doubtful, but possible) in their own form. Thus, they may have their own backing bean for their form to handle all data, including the emails, addresses, etc. The submit call would most likely go to a different bean.. so I am wondering how I get all the emails, addresses, etc in their own bean from the backing component bean I use for my composite component? What code is required I guess in a "unknown" bean to my composite component backing bean, such that the unknown bean that is handling the entire form processing can access my composite component bean to get the inputted data for emails, etc?
Any strategy that begins with "I might need a more complex EL" should be looked at very carefully. As I point out frequently, programming is something that should be done in backing beans, not on the View definition. Ideological purity notwithstanding, debugging EL is a . It's a LOT easier to debug Java code.
This is one reason I recommend using a dataTable instead of ui:repeat where possible. The dataTable pairs with a DataModel object which decorates your raw backing data with some JSF support constructs and methods. Most importantly, it adds the getRowData() method which tells your action and AJAX methods directly which row was selected without any specialized EL at all.
An IDE is no substitute for an Intelligent Developer.
Joined: Nov 14, 2011
Thank you. I tried with a dataTable. The problem is, maybe it's just my lack of know how, but the look of it looks like a data table. Rows/cells. I don't want that look. The email one is simple, but the address one is a little more full, where I want the UI to look something like:
------------- outer address component panel ----------------------------
To add another address, click [+] <ajax request to dynamically add a new set of address fields below>
---- address 1 ------
Address Type [<drop down home/work/business/other>]
Street 1: [ input box ]
Street 2: [ input box ]
Street 3: [ input box ]
State: [ drop down, when selected, cities load up]
City: [ drop down, filled in on state select]
Zip: [ possible drop down with zip codes within range of city, if not, input box with error message next to it so that they only enter numbers]
--- address 2 ---- <and so on>
----------end of outer address component panel ------------------------
There is no doubt a way to lay out the UI using datatable model, or I don't think you would have mentioned using it.. I am pretty sure from my last thread that you understood how I wanted this component to work. Not sure I clarified the UI though. I have seen address/email/phone fields in a db table layout like the default UI of a dataTable component, where you can edit inline, add more, etc. I don't like that particular look.
I do agree.. and looked it up and started working on a component with dataTable, but am still not completely clear on how to render my specific UI layout, and not the normal dataTable layout.
That said, the other thing I am not sure on, is the backing bean that contains the dataModel (for the dataTable) will obviously contain a List<Email> (or whatever object I use for each item). I get that the bean that has the dataModel with my object collection is used to render the elements in the page, but when I submit the form in it's entirety (for example, a form with the email component, the address component an the phone number component, where each can have some dynamic number of each type that a user used the + button to add and fill out).. how do I get the actual data they enter/select? I ask this because I know that any form I use this in will be submitted to a different bean completely. I am not sure how in the submit() method for that bean that a form that uses these components, gets the actual data filled in by each of the components.
Gotta say though, this is fun learning about this! I've tried lots of things and got a few things working, but these two above I have yet to figure out. Doesn't seem to be any good examples of it either that I can find. I am still trying to peace together the MVC flow and lifecycle of different components used on a page that submits to yet a different bean.
OK. Here's one possibility. First, don't try and make each UI element a distinct row in a dataTable. Make each address be a row. Within the rectangular area defined by that row, you can organize the individual elements however you wish. Think of it as being functionally similar to a <ldiv/>.
So, if I'm visualizing what you want correctly, the easy way to do this is make 2 dataTables, each 1 column wide with complex content. One table is for adding/removing email addresses, the other for adding/removing postal addresses. Each one has its own DataModel.
When you submit a form via ajax, commandButton or commandLink, the values sent to the server are bound to the value parameters of their respective input controls. In the case of a "loop variable", that can be a problem, since it's not constant the way that bean objects are. That's the advantage of the DataModel. It adds decoration (functionality) to the UI model that allows JSF to know which row of the table you are addressing. ui:repeat, unfortunately, doesn't have that option, so you'd have to kludge it. Say, by including an hidden input field to the address with its database primary key or something like that.
Joined: Nov 14, 2011
Ok..I'll give that a shot. So an entire Address or Email object is one row.. interesting and good idea.
Only question is.. will it still look like a data table with rows/column grid lines, or is their the flexibility of making it however I want? I do use primefaces as well, so looking to use p:dataTable element, which I think is just about identical to the h:dataTable.
I recommend using the h:dataTable over the p:dataTable unless you intend to take advantage of PrimeFaces-specific enhancements to the basic dataTable behavior. As a general rule, I don't like to lock myself into a given vendor/architecture unless there is a compelling reason.
Anything rendered from a datatable is inherently going to be laid out in a grid, since the HTML TABLE tag is the underlying construct. Beyond that, however, the appearance of that grid and its elements are all controllable by CSS.
Joined: Nov 14, 2011
I agree in most cases, however I am trying to use the PrimeFaces theming for our site.. there are some nice themes and I am weakest in understanding CSS layout issues across browsers, so I prefer to avoid messing with CSS if I can help it. Using colors isn't a big deal, but the themes in PrimeFaces provide various other CSS niceties. PrimeFaces 4 is due out soon which will add CSS 3 and HTML 5 I believe to most components.. not for sure yet.
That counts as a legitimate reason to use the PrimeFaces tag instead of the core tag. If you were more conversant with CSS, you'd be able to employ the PrimeFaces classes on core tags as well, but it's probably not worth the effort.