2015-07-31 8 views
8

Es gibt drei Tabellen in MySQL-Datenbank, category, sub_category und brand (Hersteller), wo category ein Elternteil des Rest also ist sub_category und brand. Ich hoffe, dass die Beziehung zwischen Menüs basierend auf den Tabellenbeziehungen klarer sein kann.Zurücksetzen Kind p: selectOneMenus innen ap: Datatable leer, wenn ein markiertes Element in ihrer Mutter Liste ausgewählt ist

Alle drei <p:selectOneMenu> s sind in einem <p:dataTable> in drei entsprechenden Spalten, wie durch <p:column> identifiziert. Ich ignoriere die <p:column>, <p:cellEditor>, <f:facet name="output">, <f:facet name="input">10, und all diese Ärgernisse der Kürze halber.

row entspricht eine JPA verwaltete Einheit, die product in diesem Fall ist, wie durch var="row" in den zugehörigen <p:dataTable> angegeben.

Dies ist die eigentlichen Fragezeichen: Wenn ein Element (die erste) mit einem null Wert im categoryList (Eltern) ausgewählt, das Kind listet subCategoryList und brandList soll Ruhe sein zu leeren.

Kategorieliste:

<p:selectOneMenu id="categoryList" 
       value="#{row.category}" 
       required="#{param['javax.faces.source'] ne component.clientId}"> 

    <f:selectItem itemLabel="Select" 
        itemValue="#{null}"/> 
    <!-- When this item is selected, its children below should be reset to empty. --> 

    <f:selectItems var="category" 
        value="#{productManagedBean.categories}" 
        itemLabel="Select" 
        itemValue="#{category}"/> 

    <p:ajax update="subCategoryList brandList"/> 
    <!-- The listener functionality is left incomplete here. --> 
</p:selectOneMenu> 

Unterliste:

<p:selectOneMenu id="subCategoryList" 
       value="#{row.subCategory}"> 

    <f:selectItem itemLabel="Select" 
        itemValue="#{null}"/> 

    <f:selectItems var="subCategory" 
        value="#{productManagedBean.getSubCategories(row.category)}" 
        itemLabel="#{subCategory.subCatName}" 
        itemValue="#{subCategory}" 
        rendered="true"/> 
</p:selectOneMenu> 

Marke (Hersteller) Liste:

<p:selectOneMenu id="brandList" 
       value="#{row.brand}"> 

    <f:selectItem itemLabel="Select" 
        itemValue="#{null}"/> 

    <f:selectItems var="brand" 
        value="#{productManagedBean.getBrands(row.category)}" 
        itemLabel="#{brand.brandName}" 
        itemValue="#{brand}" 
        rendered="true"/> 
</p:selectOneMenu> 

Die Managed Bean (faul Datenmodell im Kontext außer Acht gelassen werden dieser Frage):

@Named 
@ViewScoped 
public class ProductManagedBean extends LazyDataModel<Product> implements Serializable { 

    @Inject 
    private Service service; 

    // Associated with <p:selectOneMenu id="categoryList">. 
    private List<Category> categories; // Getter & setter. 

    // These are merely helper maps to reduce possible database calls. 
    private Map<Category, List<SubCategory>> subCategoriesByCategory; 
    private Map<Category, List<Brand>> brandByCategory; 

    public ProductManagedBean() {} 

    @PostConstruct 
    private void init() { 
     // This can be application scoped somewhere else as per business requirement. 
     categories = service.getCatgeoryList(); 

     subCategoriesByCategory = new HashMap<Category, List<SubCategory>>(); 
     brandByCategory = new HashMap<Category, List<Brand>>(); 
    } 

    // This method populates <f:selectItems> associated with <p:selectOneMenu id="brandList">. 

    public List<SubCategory> getSubCategories(Category category) { 
     // category is never null here unless something is broken deliberately. 

     if (category == null) { 
      return null; 
     } 

     List<SubCategory> subCategories = subCategoriesByCategory.get(category); 

     if (subCategories == null) { 
      subCategories = service.findSubCategoriesByCategoryId(category.getCatId()); 
      subCategoriesByCategory.put(category, subCategories); 
     } 

     return subCategories; 
    } 

    // This method populates <f:selectItems> associated with <p:selectOneMenu id="brandList">. 
    public List<Brand> getBrands(Category category) { 
     // category is never null here unless something is broken deliberately. 

     if (category == null) { 
      return null; 
     } 

     List<Brand> brands = brandByCategory.get(category); 

     if (brands == null) { 
      brands = service.findBrandsByCategoryId(category.getCatId()); 
      brandByCategory.put(category, brands); 
     } 

     return brands; 
    } 
} 

In jedem Fall wird der ausgewählte Wert in einem dieser Menüs nicht zu der entsprechenden Backing-Bean geliefert. Es ist nur in dem Modell verfügbar, das von JPA unterstützt wird (value="#{row.category}", value="#{row.subCategory}" bzw. value="#{row.brand}").

► Wie die Backing Bean signalisieren, dass das erste Element mit einem null Wert im übergeordneten Menü („Select“ markiert) ausgewählt wird, um das Zurücksetzen zu leeren dessen Kind Listen? Dies sollte auf jede mögliche Weise geschehen, wenn dies nicht möglich ist.

Ich benutze PrimeFaces 5.2 final (Community Release) und Mojarra 2.2.12.


Dies ist nicht erforderlich, es sei denn es eine Null-Fremdschlüssel in der zugrunde liegenden Datenbanktabelle in jeder (oder etwas) einen optionalen Elternteil mit dem herstellerspezifischen ON DELETE SET NULL Option speziell ist damit entsprechende Kind Reihe.

Antwort

2

Um den Punkt, müssen Sie sicherstellen, dass der <f:selectItem> Getter mit einem null Argument aufgerufen wird. Mit anderen Worten, die #{row.category} muss null sein.In Anbetracht, dass Sie für #{row.category} das Modell als unter Verwendung des in dieser Antwort gezeigt, Populate p:selectOneMenu based on another p:selectOneMenu in each row of a p:dataTable, höchstwahrscheinlich, wie unten,

@Transient 
private Category category; 

public Category getCategory() { 
    return (category == null && subCategory != null) ? subCategory.getCategory() : category; 
} 

dann wird die #{row.category} eigentlich nie null sein, wenn es ein subCategory ist. Dies ist der Fall, wenn ein vorhandener Dateneintrag im View angezeigt wird.

Sie müssen die subCategory (und brand) grundsätzlich explizit auf Null setzen, wenn die transiente category-Eigenschaft explizit auf null gesetzt ist. Dieses Versehen ist inzwischen in der erwähnten Antwort behoben. Hier ist, wie Sie Ihre neue setCategory() Methode soll wie folgt aussehen:

public void setCategory(Category category) { 
    this.category = category; 

    if (category == null) { 
     subCategory = null; 
     brand = null; 
    } 
} 

Auf diese Weise wird die getCategory() richtig null zurückkehren und damit die übergebenen in #{row.category} auch.