Victor
Victor

Reputation: 335

Wicket SELECT doesn't update it's model

i've wicket panel with list of ProductViews (as SELECT)
product list by categories
after you choose your ProductView from SELECT, its load Product from database by id of ProductView into details form. You can modify Product entity and you can save it when you finish.
details form
After save i try to refresh SELECT list to update its data, but it doesn't work(i mean, for example, SELECT contains an old name of product after rename it, but when i select the same ProductView, it reload an entity into details form again, and of course the new data appears from database) i don't want to reload product list again, i want to solve it from memory. Here is my source:

ProductView:

@Entity
@Table(name = "product")
@XmlRootElement
public class ProductView implements Serializable{

        private static final long serialVersionUID = 1L;
        @Id
        @GeneratedValue(strategy = GenerationType.IDENTITY)
        @Basic(optional = false)
        @Column(name = "id")
        private Long id;
        @Column(name = "name")
        private String name;
        @Enumerated(EnumType.ORDINAL)
        @Column(name = "category")
        private Category category;

        public ProductView() {
        }
        public ProductView(Long id) {
            this.id = id;
        }
        public ProductView(Product product) {
            this.id = product.getId();
            this.name = product.getName();
            this.category = product.getCategory();
        }
        // + getters & setters
    }

Product:

@Entity
@Table(name = "product")
@XmlRootElement
public class Product implements Serializable {
    // same as ProductView but more data, objects, connections, etc
}

And wicket panel with comments

private Product product;
private ProductView productView;
private List<ProductView> productViews;

private Form productForm;
private Select categorySelectComponent;
private WebMarkupContainer contentContainer;

public ProductPanel(String id) {
    super(id);
    setOutputMarkupId(true);

    add(contentContainer = new WebMarkupContainer("contentContainer")); // container DIV
    contentContainer.setOutputMarkupId(true); // refreshable
    contentContainer.add(productForm = new Form("productForm")); // details FORM
    contentContainer.add(categorySelectComponent = new Select("categorySelectComponent", new PropertyModel<ProductView>(this, "productView"))); // item SELECT

    categorySelectComponent.add( new SelectOptions<ProductView>( // first category
            "oneCategory",
            new PropertyModel<List<ProductView>>(this, "oneProducts"), // see getOneProducts(); list of productviews
            new IOptionRenderer<ProductView>() {
                @Override
                public String getDisplayValue(ProductView p) {
                    return p.getName();
                }
                @Override
                public IModel<ProductView> getModel(ProductView p) {
                    return new Model<ProductView>(p);
                }
            }));
    categorySelectComponent.add( new SelectOptions<ProductView>( // second category
            "twoCategory",
            new PropertyModel<List<ProductView>>(this, "twoProducts"), // see getTwoProducts();
            new IOptionRenderer<ProductView>() {
                @Override
                public String getDisplayValue(ProductView p) {
                    return p.getName();
                }
                @Override
                public IModel<ProductView> getModel(ProductView p) {
                    return new Model<ProductView>(p);
                }
            }));
    categorySelectComponent.add( new SelectOptions<ProductView>( // third category
            "threeCategory",
            new PropertyModel<List<ProductView>>(this, "threeProducts"), // see getThreeProducts();
            new IOptionRenderer<ProductView>() {
                @Override
                public String getDisplayValue(ProductView p) {
                    return p.getName();
                }
                @Override
                public IModel<ProductView> getModel(ProductView p) {
                    return new Model<ProductView>(p);
                }
            }));

    categorySelectComponent.add(new OnChangeAjaxBehavior() { // update form after choose entity
        @Override
        protected void onUpdate(final AjaxRequestTarget art) {
            product = getProductFacade().find( productView.getId() );
            updatePanel(art);
        }
    });

    productForm.add(
        // some details component (textfields, radios, links, etc) to edit Product
    );
    productForm.add(new AjaxSubmitLink("formSubmitLink") { // save entity
        @Override
        protected void onSubmit(AjaxRequestTarget art, Form<?> form) {
            super.onSubmit(art, form); // i don't know it is necessary at all
            getProductFacade().edit( product );
            updateProductViewInCategoryMap(art); // important method
            //art.add(contentContainer); //it is in update method
        }
    });
}

more methods inside panel

private Map<Category, List<ProductView>> categoryMap; // all product by categories
public void initCategoryMap() {
    categoryMap = new EnumMap<Category, List<ProductView>>(ProductView.class);
    categoryMap.put( Category.ONE,  new ArrayList<ProductView>() );
    categoryMap.put( Category.TWO,  new ArrayList<ProductView>() );
    categoryMap.put( Category.THREE,  new ArrayList<ProductView>() );

    for (ProductView view : getProductViews()) {
        categoryMap.get(view.getCategory()).add(view);
    }
}

//***** Get Products By Categories *******

final public List<ProductView> getOneProducts(){
    if (categoryMap == null){
        initCategoryMap();
    }
    return categoryMap.get( Category.ONE );
}

final public List<ProductView> getTwoCategory(){
    if (categoryMap == null){
        initCategoryMap();
    }
    return categoryMap.get( Category.TWO );
}

final public List<ProductView> getThreeProducts(){
    if (categoryMap == null){
        initCategoryMap();
    }
    return categoryMap.get( Category.THREE );
}

// **************************************

public List<ProductView> getProductViews() { // Get All Product
    if (productViews == null) {
        productViews = getProductFacade().findAllProductAsView();
    }
    return productViews;
}

private void updatePanel(AjaxRequestTarget art) { // refresh panel
    art.add(ProductPanel.this);
}

private void updateProductViewInCategoryMap(AjaxRequestTarget art) { // change Product in map after save (call from onSubmit method of AjaxSubmitLink)
    for(Map.Entry<Category, List<ProductView>> entry : categoryMap.entrySet()){ // search category contains entity
        if (entry.getValue().contains( productView )){
            entry.getValue().remove( productView ); // remove entity from category
            break;
        }
    }
    productView = new ProductView( product ); // new productview by modified product
    categoryMap.get( productView.getCategory() ).add( productView ); // add entity to it's category's list 
    art.add(contentContainer);
}

and HTML:

<select class="categorySelect" wicket:id="categorySelectComponent">
    <optgroup label="Category One">
        <wicket:container wicket:id="oneCategory">
                <option wicket:id="option"></option>
             </wicket:container>
    </optgroup>
    <optgroup label="Category Two">
        <wicket:container wicket:id="twoCategory">
                    <option wicket:id="option"></option>
            </wicket:container>
    </optgroup>
    <optgroup label="Category Three">
        <wicket:container wicket:id="threeCategory">
                <option wicket:id="option"></option>
            </wicket:container>
    </optgroup>
</select>

Any idea?

Upvotes: 0

Views: 505

Answers (2)

svenmeier
svenmeier

Reputation: 5681

Call #setRecreateChoices(true) on all your SelectOptions.

Upvotes: 1

Alexey Mukas
Alexey Mukas

Reputation: 739

What about updating productViews on saving changes or using LoadableDetachableModel instead of PropertyModel in categorySelectComponent?

here:

new Select("categorySelectComponent", new PropertyModel<ProductView>(this, "productView")

Upvotes: 1

Related Questions