9 Replies Latest reply on Nov 30, 2007 4:32 AM by Jamie Cruise

    generating forms programatically

    Steven Shaw Newbie

      Hi. I'm pretty new to Seam and JSF. I'm using it with Facelets and RichFaces/Ajax4j. I've been looking predominantly at the bookings demo as an example of how to get going. I noticed that in templates (I call all .xhtml Facelet files templates) defining forms there are a fair bit of boiler place with the instantiating of the "edit.xhtml" composition.

      I'm wondering if you can programatically create a form. This way you can even build generic forms for domain objects in your app. This technique is used by users of the Click framework and also Tapestry. Tapestry 5 seems to have some specific support for it, calling it BeanEditForm.

      Any hints about how to build a FormBuilder with Seam/JSF/Facelets/RichFaces or otherwise dealing with the boiler plate around form construction?

      One of the features I am hoping to have with my FormBuilder is to notice when the form is read-only and use output fields instead of input boxes (i.e. build a "display page" rather than an "input form"). I'd also like to hide the boilerplate for adding decorators for required fields, validation and error messages. This way I can switch the entire app over from errors at the top to errors next to fields or decide globally whether to use ajax4j for validation onblur. This should help with maintenance problems as the project evolves.

      Cheers,
      Steve.

        • 1. Re: generating forms programatically
          Pete Muir Master

          Yes, you can programmatically create component (trees) using Facelets and JSF but its a pita - Rick Hightower I think deals with this in his JSF series on developer works.

          However I would prefer to do it using Facelets compositions. What do you particularly not like about s:decorate?

          • 2. Re: generating forms programatically
            Steven Shaw Newbie

            In Hightower's "JSF for non-believers" anti-FUD series? I cannot find it. He talks about creating your own components in part 4 but I don't think it covers dynamically constructing components at runtime.

            s:decorate serves it's purpose and certainly deals with some aspects of boilerplate but it isn't a complete solution for me by itself. It doesn't build a form for me based on a bean and it's meta data (using appropriate input controls and labels etc). Neither does it solve the maintenance problem related to turning on and off ajax support for "on the fly" validation.

            You can't do this kind of thing with facelet compositions alone, can you? There's going to be reflection and logic for choosing appropriate input controls etc...

            Cheers,
            Steve.

            • 3. Re: generating forms programatically
              Pete Muir Master

              Part4 and his two articles there on facelets I think are what I meant. Thanks for enumerating your reasons for not using s:decorate - you are correct, and they aren't something we can easily address.

              You are probably best doing something like this with code - you should discuss this on the facelets mailing list as there are lots of facelets experts there.

              • 4. Re: generating forms programatically
                Jamie Cruise Newbie

                I dynamically construct forms using the c: tags. These allow you to manipulate the JSF component tree and dyanically select uicomponents to include based on your application metadata. You can't do this using tags like ui:repeat which don't change the component tree. The downside of using the c: tags is that the interactions between them and the rest of the page can get really confusing, and you end up working fairly close to the JSF lifecycle machinery during debugging.

                Cheers
                J

                • 5. Re: generating forms programatically
                  Steven Shaw Newbie

                  J, I've seen an example in my searches that used the c: tags to help with a little logic (choosing between a "display" set of components and an "edit" set of components I think). That could certainly have some uses. However, is it possible to inquire about annotations and other meta data about bean properties using only c: tags? Can you show an example, maybe I'm missing something.

                  I feel at that point, even if possible, that it is too much logic in the template. I cannot imagine that refactoring c: tags in Facelets templates would be much fun :) - I imagine we don't even have "extract method". With templating, and Facelets in particular, aren't we trying to avoid logic in the template?

                  I would love to do as Peter suggest and do it "with code". I'm just struggling to find the appropriate place to do it. Btw, I am hoping to reuse the s:decorate component from within my code, along with any other useful components. Creating my own component set seems to be quite a bit of trouble though, looking at Hightower part 4 article (seems to be at least one bug in there too). However, that is certainly one option that I am considering (it's so annoying how you have to create a Component and a Tag and a mention in the taglib.xml file!). I recently discovered Ajax4Jsf/RichFaces CDK which could help cutting down the boilerplate with that. Peter I noted that you have had similar thoughts on your blog :).

                  It seems that JSF templating convolutes the creation of the component tree and the template/layout itself. If I could create my component tree with code and lay them out in a template (amongst more static components I guess), things might be heading towards my ideal scenario.

                  I will certainly follow up with the Facelets list. Thanks for the thoughts. Keep them coming!

                  I've also come across an old article from 2004 "Improving JSF by dumping JSP". I haven't finished yet but it's starting to talk about the idea of using a programmatic view handler (instead of JSP in this case - perhaps before Facelets was around) where you can construct the component tree "in code". A custom view handler could be hard to sell to the team though :(.

                  Cheers,
                  Steve.

                  • 6. Re: generating forms programatically
                    gonzalad Apprentice

                    Hi, you can also look at http://code.google.com/p/krank/.

                    I've never used it, and never tested it. Perhaps it can help you...
                    RichardHightower is involved in this project.

                    Downsides : it doesn't build on top of Seam.

                    • 7. Re: generating forms programatically
                      Jamie Cruise Newbie

                      The general strategy that I used was:

                      1. Build some framework classes that know how to extract basic field level metadata from ejb/hibernate config info at runtime. Automatically extracted metadata includes types, lengths, relationships etc. I also provide attributes in these framework classes to add additional decorations (editable status, pick list options, custom templates types etc.)

                      2. Provide an XML based config that allows me to specify the data configurations that should appear on each form in my system, and the facelets template to be used to draw that form (e.g. a panel renderer, a grid renderer etc) and the view id for that form.

                      3. Provide a custom facelets resolver that selects the correct rendering template for each form defined in my config when the user navigates to a particular URL. In this way I don't have to have actual facelets pages on disk for each form.

                      4. Build some generic renderers that use the metadata provider classes in conjunction with the c: tags.

                      I can support 10s or 100s of entity types in my system supported by only a couple of generic renderers.

                      I don't know if this is all a great idea, but it works for me!

                      Cheers
                      J

                      • 8. Re: generating forms programatically
                        Steven Shaw Newbie

                        Thanks J! That sounds similar to what I am thinking except that I prefer avoid custom XML and would more than likely build up the configuration (for the Facelets templates to forward to) in code.

                        Your framework classes are what I am thinking of as my "FormBuilder". They use whatever metadata they can get their hands on but can be overridden where necessary. The "custom facelets resolver" was the missing piece for me. Thanks so much for your post.

                        If you have time I'd love to hear more about your ideas. Still not sure about the c: logic tags in the "generic renders" - why do you need it? Why do you need to build a renderer?

                        Have you been able to separate layout from the component tree construction? i.e. can you build a form with metadata and then lay it out in the Facelets template specifying different parts of the form in separate fieldsets for instance? This is the approach taken for the tail end of the article Improving JSF by dumping JSP.

                        Cheers,
                        Steve.

                        • 9. Re: generating forms programatically
                          Jamie Cruise Newbie

                          The renderers are just the metadata-driven generic form templates. I chose to use facelets to generate the forms rather than building custom jsf controls because it has such great composition functionality. I considered writing a jsf control for a custom grid or panel that was driven by my metadata model components. However, that seemed like hard, error prone work and it would be difficult to keep up with the state of the art in JSF gui's. In essence I didn't want to be building yet another JSF GUI lib. So I use facelets to dynamically build the higher level UI abstractions on top of the component set du jour.

                          The form templates (renderers) basically just loop over metadata using c:forEach to insert fields components into the page. I use facelets source tags for the "master" field component (to make the parameter passing nice), and within that I use ui:include with an expression for the src attribute to dynamically include correct jsf tags for the particular field type.

                          The essence of this approach is that the c: tags are processed before the rest of the jsf lifecycle processing, so they effectively act as a component tree generator.

                          Hope this helps.

                          Cheers
                          J