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.