Announcement Announcement Module
Collapse
No announcement yet.
JSF + Master-Detail Pattern Page Title Module
Move Remove Collapse
X
Conversation Detail Module
Collapse
  • Filter
  • Time
  • Show
Clear All
new posts

  • JSF + Master-Detail Pattern

    Hi SWF Community,

    I'm using SWF + JSF to create an application (in details its SWF 1.0.2 and JSF 1.2).
    I've looked at the example projects given with SWF and missing something important (maybe not only to me). There is no example on how to use a Master-Detail Pattern with JSF.
    Ok, I can use the TableData class from JSF or use f:setProperyActionListener, but both aproches are totaly 'out of the flow'. There is no need for SWF then which is a pitty, because SWF gives me much more options in page flow that JSF on it's own does.
    So is there any good practice or example how to implement master-detail with SWF and JSF?

    Thansk for any ideas.

  • #2
    The Phonebook sample application shows a master-detail scenario. It's not a JSF based example but should still be helpfull.

    Erwin

    Comment


    • #3
      Yep, I've seen that, but it does not really match into JSF I think.
      It uses a GET request with parameters for the detail selection (as far as I remember). But this is not an option in JSF using a tableData list of rows.
      Maybe I have to reread it. Any other ideas?

      Comment


      • #4
        I've found a solution I want to share with the community. If there are any comments or ideas for better ways feel free to post here:

        The JSF master view:
        HTML Code:
        <h:dataTable value="#{springService.list}" var="row">
        ...
          <h:column>
            <h:commandButton value="Details" action="details">
              <f:setPropertyActionListener value="#{row.primaryKey}" target="#{swfVar.primaryKey}" />
            </h:commandButton>
          </h:column>
        </h:dataTable>
        The flow definition:
        HTML Code:
        ...
        <var name="swfVar" class="some.Class" scope="flow" />
        ...
        <view-state id="details" view="/details.jsf">
          <render-actions>
            <bean-action bean="springService" method="readDetails">
              <method-arguments>
                <argument expression="flowScope.swfVar" />
              </method-arguments>
              <method-result name="swfVar" scope="flow" />
            </bean-action>
          </render-actions>
        </view-state>
        The spring service reads the details for the given object (either from dbms or other source) and returns the reference which in turn is stored in flowScope again.

        Then the JSF details view could use the swfVar variable to render the result.

        Comment


        • #5
          You may hit problems if you turn on sort and pagination because the render action will be called everytime.

          Comment


          • #6
            Thanks for the hint. An entry action would be better then I guess.

            Comment


            • #7
              I've found that still has problems sadly with JSF.

              Comment


              • #8
                Master-Detail Scenario seams to be a pain.
                I am using JSF 1.1 - Myfaces.
                How can this be done with SWF & JSF 1.1? Any hints?

                Torsten

                Comment


                • #9
                  Some more thought about it:

                  The Flow gets started in Render Response Phase through the PhaseListener, am i right?
                  But the updateActionListener is invoked on Phase 5 - the bean declared at my flow is not yet instantiated, any thoughts about this?

                  Torsten

                  Comment


                  • #10
                    Master-Detail Scenario seams to be a pain.
                    provide more detail.

                    Comment


                    • #11
                      Originally posted by jamesclinton View Post
                      provide more detail.
                      Did it in my second post.
                      Using updateActionListener fails, as the bean declared in the flow config cannot be found in Invoke Application Phase, Flow is started after that, too late.
                      Using the faram Tag does not work too.

                      Is there any "known" supported way, doing a master-detail scenario with SWF and JSF (v1.1)?

                      Comment


                      • #12
                        In a prototype that I am working on to evaluate JSF, SWF, and facelets I implemented a master detail as follows: (my prototype has a search page in which the results are displayed on the same page as the search criteria)

                        Code:
                        <form id="searchForm" jsfc="h:form">
                          <label for="searchField" jsfc="h:outputLabel" value="#{bundle.lastName}" />: <br/>
                          <input type="text" jsfc="h:inputText" id="searchField" value="#{searchBean.searchModel.searchField}" required="true" size="20"/><br/>
                          <input type="submit" jsfc="h:commandButton" id="submit"
                                         action="#{searchBean.search}" value="Submit" />
                        </form>
                        <h:form id="resultsForm">
                          <h:dataTable value="#{searchBean.searchModel.results}" var="item"
                            rowClasses="oddRow, evenRow" headerClass="tableHeader"
                            rendered="#{searchBean.searchModel.results.rowCount > 0}">
                                    <cvg:column entity="#{item}" fieldName="firstName" backingBean="#{searchBean.searchModel}" bundle="#{bundle}"/>               
                                    <cvg:column entity="#{item}" fieldName="lastName" backingBean="#{searchBean.searchModel}"  sort="#{true}"  bundle="#{bundle}"/>               
                                    <cvg:column entity="#{item}" fieldName="address" backingBean="#{searchBean.searchModel}" bundle="#{bundle}"/>               
                                    <cvg:columnCommand label="edit" action="edit" backingBean="#{searchBean.searchModel}" bundle="#{bundle}" />
                                  </h:dataTable>
                                </h:form>
                        With the latest SWF 1.0.3 changes I think I could have referred to the flow-scoped searchModel directly without going through the backing bean.

                        The cvg:column and columnCommand tags are custom facelet tags based on an article by Rich Hightower. The columnCommand, which is my link to my detail is defined as follows:

                        Code:
                        <ui:composition>
                          <c:if test="#{empty label}">
                              <c:set var="label" value="#{action}" />
                          </c:if>
                          <h:column>
                              <f:facet name="header">
                                <h:panelGroup>
                                  #{bundle[label]}
                                </h:panelGroup>
                              </f:facet>
                              <h:commandLink id="edit" value="#{label}" 
                                             action="edit">
                              </h:commandLink>
                            </h:column>
                        </ui:composition>
                        Here is my flow definition:
                        Code:
                        <flow xmlns="http://www.springframework.org/schema/webflow"
                              xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
                              xsi:schemaLocation="http://www.springframework.org/schema/webflow
                                                  http://www.springframework.org/schema/webflow/spring-webflow-1.0.xsd">
                                                    
                          <var name="searchModel" bean="searchFlowBean" scope="flow"/>
                        
                          <start-state idref="searchView" />
                        
                          <view-state id="searchView" view="/search.xhtml">
                            <transition on="edit" to="editCustomer"/>
                          </view-state>
                        
                          <subflow-state id="editCustomer" flow="editCustomer-flow">
                            <attribute-mapper>
                              <input-mapper>
                                <mapping source="${flowScope.searchModel.results.rowData.oid}" target="id" />
                              </input-mapper>
                            </attribute-mapper>
                            
                            <transition on="finish" to="searchView"/>
                          </subflow-state>
                          <import resource="search-flow-beans.xml" />
                        </flow>
                        My searchBean search method returns null so control is returned to the search view and the results are displayed (that is why you do not see a transition for the search.

                        Here is the flow definition for the edit page which picks up the oid (from my results structure) for the item to be displayed:
                        Code:
                        <flow xmlns="http://www.springframework.org/schema/webflow"
                              xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
                              xsi:schemaLocation="http://www.springframework.org/schema/webflow
                                                  http://www.springframework.org/schema/webflow/spring-webflow-1.0.xsd">
                                                    
                          <input-mapper>
                            <input-attribute name="id"/>
                          </input-mapper>
                          
                          <start-state idref="customerView" />
                        
                          <view-state id="customerView" view="/customer.xhtml">
                            <render-actions>
                              <bean-action bean="customerAction" method="getCustomer">
                                <method-arguments>
                        	  <argument expression="flowScope.id" />
                        	</method-arguments>
                                <method-result name="customer" scope="flow"/>
                              </bean-action>
                            </render-actions>
                            <transition on="save" to="finish">
                              <!-- not implemented yet
                              -->
                            </transition>
                          </view-state>
                        
                          <end-state id="finish" />
                        
                          <import resource="editCustomer-flow-beans.xml" />
                        </flow>
                        Not sure if this is a recommended way but it does work for me.

                        Comment


                        • #13
                          Thx for the example - some questions.
                          Your datatable & model are also defined in the webflow definition, if you would do this outside with pure JSF, would this work too?
                          But i can put this too in the flow, not that problem.

                          The really interesting question - how did you define the "id" which is transferred to the input mapper.

                          <mapping source="${flowScope.searchModel.results.rowData.oi d}" target="id" />

                          Your action is only "edit" - how do you define, which row was clicked? How do you set "flowScope.searchModel.results.rowData.oid".
                          As i dont know your bean, i cant guess how do you do it - so a little bit more insight, how you define the row clicked would be nice (actionListener or something ... ).

                          In pure JSF i would use faram or t:updateActionListener, but they dont work with SWF yet, so thats the interesting part to me, as i dont see how the clicked row and the oid value are bind together.

                          thx

                          Comment


                          • #14
                            Neo:

                            With JSF 1.2 you can use f:setPropertyActionListener and it does work with SWF. So I guess this could also work with the ADF version if you are limited to JSF 1.1. You could give that try.
                            You could see an example in my first example early on this topic.

                            Also to note:
                            I guess msauer is using a TableModel in its backing bean and the rowData attribute of that is the selected row (that is pure JSF without any action listeners needed).
                            Last edited by KnisterPeter; Apr 26th, 2007, 02:40 AM.

                            Comment


                            • #15
                              The problem that I was trying to solve was how to make use of a bound UIComponent in a web flow. I could bind the data table to my request scoped backing bean but I was not able to use that backing bean in the web flow. I also could not bind the data table to my flow scoped model due to serialization. (I think some of this may be fixed in Jeremy's work on making the EL available in the flow.) So, not being able to do the binding, I took this approach as an alternative.
                              So some additional info on what I did...
                              I defined a request scoped backing bean and had my flow model injected into it:
                              Code:
                                <managed-bean>
                                  <managed-bean-name>searchBean</managed-bean-name>
                                  <managed-bean-class>com.convergys.SearchController
                                  </managed-bean-class>
                                  <managed-bean-scope>request</managed-bean-scope>
                                  <managed-property>
                                    <property-name>searchModel</property-name>
                                    <value>#{searchModel}</value>
                                  </managed-property>
                                </managed-bean>
                              My backing bean has the following:
                              Code:
                                public String search() {
                                  searchModel.getResultsList().clear();
                                  // now add new results to results list
                                  return null; // <--this is required for JSF not to invoke navigation
                                }
                              My model class has the following:
                              Code:
                                private List<SearchResult> resultsList = new ArrayList<SearchResult>();
                                private transient ListDataModel results;
                              
                                public ListDataModel getResults() {
                                  if (results == null) {
                                    results =  new ListDataModel(resultsList);
                                  }
                                  return results;
                                }
                              Regarding the id transferred to the input mapper... My SearchResult class has an int oid field. Via the input mapper SWF took that int value and set the flowscope variable id in the sub flow. I then used that in my getCustomer method which is defined as follows:
                              Code:
                                public Customer getCustomer(int oid) {
                              As far as which row is clicked, that is handled by the DataTable value binding to the results attribute of the model. I did not have to do anything special to get the clicked item.

                              Again, I am new to this and this may not be the best way so I welcome any comments.
                              The suggestion of using f:setPropertyActionListener is intriguing.
                              Last edited by msauer; Apr 26th, 2007, 08:27 AM.

                              Comment

                              Working...
                              X