Wicket SELECT не обновляет свою модель
У меня есть панель калитки со списком ProductViews (как SELECT)
после того, как вы выбрали ProductView из SELECT, загрузите Product из базы данных по id ProductView в форму сведений. Вы можете изменить сущность Product и сохранить ее, когда закончите.
После сохранения я пытаюсь обновить список SELECT, чтобы обновить его данные, но он не работает (я имею в виду, например, SELECT содержит старое имя продукта после его переименования, но когда я выбираю тот же ProductView, он перезагружает объект в детали формируются снова, и, конечно, новые данные появляются из базы данных) я не хочу снова загружать список продуктов, я хочу решить его из памяти. Вот мой источник:
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
}
Товар:
@Entity
@Table(name = "product")
@XmlRootElement
public class Product implements Serializable {
// same as ProductView but more data, objects, connections, etc
}
И калитка с комментариями
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
}
});
}
больше методов внутри панели
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);
}
и 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>
Любая идея?
2 ответа
Вызовите #setRecreateChoices(true) для всех ваших SelectOptions.
Как насчет обновления productViews
при сохранении изменений или использовании LoadableDetachableModel
вместо PropertyModel
в categorySelectComponent
?
Вот:
new Select("categorySelectComponent", new PropertyModel<ProductView>(this, "productView")