当选择父列表中的标记项目时,将p:dataTable中的子p:selectOneMenus重置为空。

8
MySQL数据库中有三个表,categorysub_categorybrand(制造商),其中category是其余表的父表,即sub_categorybrand。希望基于表关系可以使菜单之间的关系更加清晰。
所有三个<p:selectOneMenu>都位于一个<p:dataTable>内的三个相应列中,由<p:column>标识。为了简洁起见,忽略<p:column><p:cellEditor><f:facet name="output"><f:facet name="input"><p:rowEditor>以及所有此类麻烦。 row对应于JPA管理的实体,在本例中为product,由与<p:dataTable>关联的var="row"指定。 这是实际的疑问:当选择categoryList(父)中具有空值的项目(第一个项目)时,其子列表subCategoryListbrandList应重置为空。
类别列表:
<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>

子类别列表:

<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>

品牌(制造商)列表:

<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>

托管Bean(在此问题的上下文中可以忽略惰性数据模型):
@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;
    }
}

在任何情况下,这些菜单中选择的值都没有提供给相应的后台bean。它只在被JPA支持的模型中可用(分别是value="#{row.category}"value="#{row.subCategory}"value="#{row.brand}")。
如何向后端bean发信号,以便在父级菜单中选择了具有null值(标记为“Select”)的第一个项目,从而将其子列表重置为空?如果不可行,则应以任何可行的方式进行。
我正在使用PrimeFaces 5.2 final(社区版本)和Mojarra 2.2.12。
除非底层数据库表中存在空外键,特别是使用供应商特定的ON DELETE SET NULL选项,允许每个(或一些)相应的子行中有一个可选的父行,否则不需要这样做。
1个回答

2
要点是,您需要确保用一个null参数调用<f:selectItem>的getter方法。换句话说,#{row.category}必须为null。鉴于您正在使用此答案中显示的模型来获取#{row.category}在p:dataTable的每一行中基于另一个p:selectOneMenu填充p:selectOneMenu,如下所示:
@Transient
private Category category;

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

如果存在subCategory,那么#{row.category}实际上永远不会为null。当在视图中呈现现有数据条目时,就会出现这种情况。

基本上,当瞬态category属性被明确设置为null时,需要显式将subCategory(和brand)设置为null。这个疏忽已经在提到的答案中得到修复。这是您新的setCategory()方法应该像的样子:

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

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

这样一来,getCategory() 将会正确地返回 null,因此传入的 #{row.category} 也将是 null


网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接