3 Replies Latest reply on Mar 13, 2006 3:00 AM by Jens Weintraut

    Problem applying a filter on a @DataModel

    Jens Weintraut Apprentice

      Hi folks,

      one of my Seam components holds a @DataModel with a @DataModelSelection and a @DataModelSelectionIndex. Now I've got a problem when I try to filter my @DataModel. The filtering is done with a <h:selectOneMenu>. As soon as a SelectItem is choosen the page is submitted via onchange="submit()". Then the factory method is invoked where I set the @DataModel depending on the SelectItem. Debugging this method shows me, that this works fine. But when the page is redisplayed, the list is unchanged. There are still the same elements shown, although the @DataModel in the component was updated.

      Has anybody any idea, why this happens?

      Here is some code:

      The component which holds the @DataModel

      @Stateful
      @Scope(ScopeType.SESSION)
      @LoggedIn
      @Name("showListForDevelopers")
      @Interceptors(SeamInterceptor.class)
      public class ShowListForDevelopers implements IShowListForDevelopers, Serializable {
       @PersistenceContext(unitName = "aresDatabase")
       private EntityManager em;
      
       @In @Valid
       private User user;
      
       @DataModel
       @Out
       private List<Testaction> testactions;
      
       @DataModelSelection
       @Out(required=false)
       private Testaction currentTestaction;
      
       @DataModelSelectionIndex
       @Out
       private int testactionIndex;
      
       @In(required=false)
       private Release selectedRelease;
      
       @In(required=false)
       private List<Release> allReleases;
      
       @Factory("testactions")
       public void getTestactions() {
       if(selectedRelease != null) {
       testactions = em.createQuery(
       "from Testaction where TACT_DEV_USR_ID=:dev and TACT_REL_ID=:rel and (TACT_REV_ID is null or TACT_REV_ID=9) order by TACT_ID asc"
       ).setParameter("dev", user.getID()).setParameter("rel", selectedRelease.getID()).getResultList();
       } else {
       testactions = em.createQuery(
       "from Testaction where TACT_DEV_USR_ID=:dev and (TACT_REV_ID is null or TACT_REV_ID=9) order by TACT_ID asc"
       ).setParameter("dev", user.getID()).getResultList();
       }
       testactionIndex = 0;
       if( testactions.size() > 0 ) {
       currentTestaction = testactions.get(0);
       }
       }
      
       public String select() {
       return "selected";
       }
      
       @Remove @Destroy
       public void destroy() {
       }
      }


      The page which displays the list:
      <h:form>
       <div id="release">
       <h:outputText value="#{ares_messages.release}: " />
       <h:selectOneMenu value="#{releaseSelector.selectedRelease}" onchange="submit()">
       <f:selectItems value="#{releaseSelector.releaseItems}" />
       </h:selectOneMenu>
      
       </div>
      
       <t:dataTable value="#{testactions}" var="testaction_var">
       <h:column>
       <f:facet name="header">
       <h:outputText value="#{ares_messages.label_testaction_ID}" />
       </f:facet>
       <h:commandLink value="#{testaction_var.ID}" action="#{showListForDevelopers.select}"/>
       </h:column>
       <h:column>
       <f:facet name="header">
       <h:outputText value="#{ares_messages.label_testaction_TCaseToken}" />
       </f:facet>
       <h:outputText value="#{testaction_var.TCaseToken}" />
       </h:column>
       </t:dataTable>
      
       <div class="errors"><h:messages globalOnly="true"/></div>
      </h:form>


      The component managing the dropdown box:
      @Stateful
      @Scope(ScopeType.SESSION)
      @LoggedIn
      @Name("releaseSelector")
      @Interceptors(SeamInterceptor.class)
      public class ReleaseSelection implements IReleaseSelector {
       @PersistenceContext(unitName = "aresDatabase")
       private EntityManager em;
      
       @Out(required=false)
       private Release selectedRelease;
      
       @Out
       private List<Release> allReleases;
      
       public List<Release> getReleases() {
       allReleases = em.createQuery("from Release order by REL_TOKEN asc").getResultList();
       return allReleases;
       }
      
       public SelectItem[] getReleaseItems() {
       List<Release> releases = getReleases();
       SelectItem[] result = new SelectItem[releases.size()];
       int i = 0;
       for (Iterator<Release> iter = releases.iterator(); iter.hasNext();) {
       Release element = iter.next();
       result[i++] = new SelectItem(element.getID(), element.getRelToken());
       }
       return result;
       }
      
       public Long getSelectedRelease() {
       if(selectedRelease != null) {
       return selectedRelease.getID();
       }
       List<Release> releases = getReleases();
       if (releases.size() == 0) {
       return Long.valueOf(0);
       }
       return Long.valueOf(releases.get(0).getID());
       }
      
       public void setSelectedRelease(Long p_ReleaseID) {
       if(p_ReleaseID == null) {
       p_ReleaseID = Long.valueOf(0);
       }
       List<Release> results = em.createQuery("from Release where ID = :id").setParameter("id", p_ReleaseID).getResultList();
       selectedRelease = results.get(0);
       }
      }


      As you can see, I inject the selectedRelease (selected filter element) and allReleases (the complete list of filter elements) into the component holding the @DataModel. This works fine.

      Thanks
      Newlukai

        • 1. Re: Problem applying a filter on a @DataModel
          Jim Hazen Expert

          There sure is a lot going on here. It'll give it a shot though.

          I've been through this a couple of times, and don't see where you ever update your testactions datamodel component. @Factory only initializes components that aren't yet defined in any scope. In your case you don't seem to update testactions in any action listener, and your testactions component has session scope. Once set, your @Factory has done all it's going to do.

          Try either:
          1. Doing something in showListForDevelopers.select()
          2. Setting the scope of your testactions to EVENT (@DataModel(scope=ScopeType.EVENT)) so that you re-@Factory on each request.

          I'd probably go with #1

          • 2. Re: Problem applying a filter on a @DataModel
            Jens Weintraut Apprentice

            Hmm. OK. But, I had a breakpoint in the @Factory and this method was called each time the user selected a filter. Just to understand it right: Seam invoked the @Factory each time the form was submitted but didn't update the changes made to testactions because there was already a testactions in session scope?

            Thanks for your hints. But I would go with #2, because the updated testactions should be displayed directly after selecting a filter. That's the reason why I've set the onchange attribute of the <h:selectOneMenu> to submit(). This way I immediatly get the selected filter and can apply it on the testactions.
            If I apply the filter in showListForDevelopers.select() it could happen that the user selects a testaction which doesn't match to the selected filter.

            I'll tell you if it works.

            • 3. Re: Problem applying a filter on a @DataModel
              Jens Weintraut Apprentice

              Good morning,

              damn traffic jams. OK. I tested your proposal. Then I got this error:

              java.lang.IllegalArgumentException: @DataModel scope must be ScopeType.UNSPECIFIED or ScopeType.PAGE: showListForDevelopers


              So, I tested the ScopeType.PAGE and have to say: it works. Thank you very much.

              I wouldn't ask if it weren't important for me. But perhaps you have an idea about this problem: http://www.jboss.com/index.html?module=bb&op=viewtopic&t=78947