8 Replies Latest reply on Sep 20, 2006 10:57 AM by Joe DeStefano

    PAGE scope DataModel's selection not correct

    Joe DeStefano Newbie

      I've got a PAGE scope DataModel which was working fine until I added an inputText tag to the page. Now the selection is always the first one on the list. I know I've had some trouble understanding exactly how DataModels (and Seam in general, really) works, so I thought I'd post this here to see if someone can educate me before I declare that there's a bug.

      I've boiled my code down to isolate the problem. I have this bean:

      @Stateful
      @Scope(ScopeType.SESSION)
      @Name("foo")
      public class FooBean implements Serializable, Foo
      {
       static final long serialVersionUID = -6536629890251170098L;
      
       private static Log log = LogFactory.getLog(FooBean.class);
      
       public FooBean()
       {
       }
      
       private String text;
       public String getText()
       {
       return text;
       }
       public void setText(String text)
       {
       this.text = text;
       }
      
       @DataModel(scope=ScopeType.PAGE)
       List<String> names;
       @DataModelSelection
       private String selectedName;
      
       public String dummy()
       {
       log.debug("Selected name is " + selectedName);
       return null;
       }
      
       @Factory("names")
       public void refresh() {
       names = new LinkedList<String>();
       names.add("Fred");
       names.add("Wilma");
       names.add("Barney");
       names.add("Betty");
       }
      
       @Destroy
       @Remove
       public void destroy()
       {
       }
      }
      


      and this page:

       <body>
       <h:form>
      <!-- <h:inputText value="#{foo.text}"/> -->
       <h:dataTable value="#{names}" var="name">
       <h:column>
       <f:facet name="header">
       <h:outputText value="Name" />
       </f:facet>
       <h:outputText value="#{name}" />
       </h:column>
      
       <h:column>
       <f:facet name="header">
       <h:outputText value="Action"/>
       </f:facet>
       <h:commandButton action="#{foo.dummy}" value="Test"/>
       </h:column>
       </h:dataTable>
       </h:form>
       </body>
      



      It works fine unless I un-comment the inputText field, in which case the dummy() method always reports that I selected the first name.

      What am I doing wrong?

      Thanks,

      Joe


        • 1. Found the cause but not the cure
          Joe DeStefano Newbie

          I've figured out why this is happening, but I don't know how to fix it yet. The problem is this: Each time a method on my bean gets called, the DataModel is injected/outjected, and a new DataModel is created to wrap my list. The JSF implementation, however, continues to use the first one outjected, so when it finally sets the rowIndex for my selected item, it is on a DataModel that is no longer accessible from Seam (it has been replaced by subsequent outjections). Without the extra form field, there's only one call to my bean, so there's no problem.

          Although I'm less lost when wandering around the Seam source these days, this seems like a deeper fix than my limited understanding can supply. Do any Seam gurus out there have some advice on how to go about fixing this? I'll give it a try myself, but a couple of starting pointers would be welcome.

          Thanks,

          Joe

          • 2. Re: PAGE scope DataModel's selection not correct
            Pete Muir Master

             

            The JSF implementation, however, continues to use the first one outjected


            This is because you are outjecting to the page scope. Why don't you outject the DataModel to the Session scope (same as the bean). It's unusual IMO to outject to a shorter lived scope than the managing bean.

            • 3. Re: PAGE scope DataModel's selection not correct
              Joe DeStefano Newbie

              Thanks for the info. Changing the bean to be page scoped made the selection work again, but it breaks some behavior in my app. The real bean in my app lets the user enter search text into the text field, and shows the results in the list. The data from which the list is generated, however, is being changed asynchronously, by processes unaware of these beans, so I want the list regenerated each time the user comes to the page. I want the search text to remain for the session, so I have a session-scoped bean with a page-scoped list. Is there a better way?


              In any case, even though my use may be wacky, it seems like it should still work, no? The DataModel is supposed to be page scoped, not individual-call-to-my-bean scoped, so I'd expect all the calls in the restore view phase to see the same one.

              • 4. Re: PAGE scope DataModel's selection not correct
                Joe DeStefano Newbie

                I made a cheap hack in outjectDataModelList() in Component.java that made things work as I expected (for a page-scoped DataModel in a session-scoped bean). I changed this:

                 context.set( name, wrapper.wrap(dataModelAnn, list));
                


                to this:

                 if(existingDataModel != null) {
                 ((javax.faces.model.DataModel) existingDataModel).setWrappedData(list);
                 } else {
                 context.set( name, wrapper.wrap(dataModelAnn, list));
                 }
                


                I don't understand the bigger picture well enough to know if that is going to hurt me in other ways, though. Will reusing the wrapper cause problems with non-PAGE-scoped DataModels, or perhaps there are other uses of DataModels that will break? Is it always safe to cast to javax.faces.model.DataModel?

                Of course, any advice on how to implement my app without using a page-scoped datamodel in a session-scoped bean is welcome, too.

                Thanks,

                Joe



                • 5. Re: PAGE scope DataModel's selection not correct
                  Gavin King Master

                  I still don't understand the problem, but is it similar to this JIRA issue:

                  http://jira.jboss.com/jira/browse/JBSEAM-308

                  • 6. Re: PAGE scope DataModel's selection not correct
                    Chris Rudd Newbie

                    The core of the problem is that even though the actual list instance that is being wrapped did not change, the code outjects a new wrapper. If the code is updated to preserve the existing wrapper if the underlying wrapped data is not changed then the problem goes away. (This is the fix proposed in http://jira.jboss.com/jira/browse/JBSEAM-308)

                    Brief overview of the flow that occurs :

                    Decode Phase:
                    UIInput decodes itself.
                    UIData grabs the DataModel (instance 1) via the value binding and caches it then decodes each row.

                    UpdateModel Phase:
                    UIInput calls setText via value binding.
                    Injection -- Existing DataModel (instance 1, the same that UIData is caching) is injected into FooBean
                    Outjection -- The list backing the datamodel does not change but a new wrapper is created and outjected (instance 2)
                    UIData iterates over its cached DataModel(instance 1)

                    InvokeApplication Phase
                    UIData fires the its ActionEvent, sets the appropriate row on the cached DataModel (instance 1).
                    UICommand calls dummy via method binding
                    Injection -- Existing DataModel (instance 2, which was oujected because of call to setText) is injected along with its selection (currently row 0, as the UIData set the row on instance 1 instead of instance 2)
                    Outjection -- The list backing the datamodel does not change but a new wrapper is created and outjected (instance 3)








                    UIData caches its DataModel reference
                    If any components are caching the outjected value (which is the case with a UIData) they wont be working on the "current" value in the contexts. Later when injection occurs the "current" value (which is no longer the same as the instance

                    • 7. Re: PAGE scope DataModel's selection not correct
                      Chris Rudd Newbie

                      Ignore that last paragraph, I rewrote the message and didnt realize I had that at the bottom =)

                      • 8. Re: PAGE scope DataModel's selection not correct
                        Joe DeStefano Newbie

                        Thanks! I didn't see that issue when I searched for "DataModelSelection incorrect" (and a few others). Next time I'll do a more general search (like just "DataModelSelection") and browse through all the results.

                        Is this something I can volunteer to fix? I've never contributed before, but I'll go read all the how-to-contribute docs and give it a try if that would be welcome.