2017-10-08 144 views
2

在自動完成中,我按預期得到產品名稱。如何獲得百里香選擇選項中的對象?

我想根據所選產品進行一些計算。但在doCalculation函數我得到id,而不是'價格'。所以計算不能按預期工作。

假設如果我更改String idExpression = "#{price}";,則計算按預期工作,但未保存訂單。由於得到如下錯誤

Failed to convert property value of type [java.lang.String] to required type [com.myapp.domain.Product] for property product; nested exception is 
org.springframework.core.convert.ConversionFailedException: Failed to convert from type [java.lang.String] to type [@javax.persistence.OneToOne 
@io.springlets.format.EntityFormat com.myapp.domain.Product] for value 2500; nested exception is java.lang.IllegalStateException: Parsers are not allowed to return null: [email protected] 

所以我想要得到的價格計算在同一時間保存功能不應該被打破。現在無論是第一還是第二都在爲我工作。

ProductsCollectionThymeleafController.java

@GetMapping(produces = MediaType.APPLICATION_JSON_VALUE, name = "select2", value = "/s2") 
@ResponseBody 
public ResponseEntity<Select2DataSupport<Product>> select2(GlobalSearch search, Pageable pageable, 
     Locale locale) { 
    Page<Product> products = getProductService().findAll(search, pageable); 
    String idExpression = "#{id}"; 
    Select2DataSupport<Product> select2Data = new Select2DataWithConversion<Product>(products, 
      idExpression, getConversionService()); 
    return ResponseEntity.ok(select2Data); 
} 

OrderCollectionThymeleafController.java

@PostMapping(name = "create") 
public ModelAndView create(@Valid @ModelAttribute Order order, BindingResult result, 
     Model model) { 
    if (result.hasErrors()) { 
     populateForm(model); 
     return new ModelAndView("/order/create"); 
    } 

    Order newOrder = getOrderService().save(order); 
    UriComponents showURI = getItemLink().to(OrderItemThymeleafLinkFactory.SHOW) 
      .with("order", newOrder.getId()).toUri(); 
    return new ModelAndView("redirect:" + showURI.toUriString()); 
} 

orderview.html

<form class="form-horizontal validate" method="POST" data-th-object="${order}" data-th-action="@{${collectionLink.to('create').with('order', order.id)}}"> 

     <fieldset id="containerFields"> 
<div class="form-group has-error has-feedback" data-z="3c00987d" id="servicio-product-field" data-th-classappend="${#fields.hasErrors('product')}? 'has-error has-feedback'" data-th-class="form-group" data-th-with="collectionLink=${@linkBuilder.of('ProductsCollectionThymeleafController')}"> 
<label for="product" class="col-md-3 control-label" data-th-text="#{label_servicio_product}">Product</label> 
<div class="col-md-6"> 
    <!-- Select2 --> 
    <select data-th-field="*{product}" onChange="doCalculation()" class="form-control dropdown-select-ajax" data-allow-clear="true" data-data-ajax--url="${collectionLink.to('select2')}" data-ajax--cache="true" data-ajax--delay="250" data-ajax--data-type="json" data-data-placeholder="#{info_select_an_option}"> 
     <option data-th-unless="*{product} == null" data-th-value="*{product.id}" data-th-text="*{{product}}" selected="selected">Product</option> 
    </select> 
    <span data-th-classappend="${#fields.hasErrors('product')}? 'glyphicon glyphicon-remove form-control-feedback'" class="glyphicon glyphicon-remove form-control-feedback" data-th-if="${#fields.hasErrors('product')}" aria-hidden="true"></span> 
    <span id="product-error" class="help-block" data-th-if="${#fields.hasErrors('product')}" data-th-errors="*{product}">Error message.</span> 
</div> 

<script> 
    function doCalculation() { 

         var price = document.getElementById("product").value; 
         alert("price: " + price); 
          //Do some calculation     } 
        doCalculation(); 
    </script> 
    </fieldset> 
    </form> 

Product.java

import java.util.Objects; 

    import javax.persistence.Entity; 
    import javax.persistence.Enumerated; 
    import javax.persistence.FetchType; 
    import javax.persistence.GeneratedValue; 
    import javax.persistence.GenerationType; 
    import javax.persistence.Id; 
    import javax.persistence.Version; 
    import javax.validation.constraints.Min; 

    import org.springframework.format.annotation.NumberFormat; 
    import org.springframework.roo.addon.javabean.annotations.RooEquals; 
    import org.springframework.roo.addon.javabean.annotations.RooJavaBean; 
    import org.springframework.roo.addon.javabean.annotations.RooToString; 
    import org.springframework.roo.addon.jpa.annotations.entity.RooJpaEntity; 

    import io.springlets.format.EntityFormat; 

    /** 
    * = Product 
    * 
    * TODO Auto-generated class documentation 
    * 
    */ 
    @RooJavaBean 
    @RooToString 
    @RooJpaEntity 
    @RooEquals(isJpaEntity = true) 
    @Entity 
    @EntityFormat 
    public class Product { 

/** 
* TODO Auto-generated attribute documentation 
* 
*/ 
@Id 
@GeneratedValue(strategy = GenerationType.AUTO) 
private Long id; 

/** 
* TODO Auto-generated attribute documentation 
* 
*/ 
private String productName; 

@Min(1L) 
@NumberFormat 
private Integer price; 

/** 
* TODO Auto-generated attribute documentation 
* 
*/ 
@OneToOne(fetch = FetchType.LAZY) 
@EntityFormat 
private Order order; 

/** 
* TODO Auto-generated attribute documentation 
* 
*/ 
public static final String ITERABLE_TO_ADD_CANT_BE_NULL_MESSAGE = "The given Iterable of items to add can't be null!"; 

/** 
* TODO Auto-generated attribute documentation 
* 
*/ 
public static final String ITERABLE_TO_REMOVE_CANT_BE_NULL_MESSAGE = "The given Iterable of items to add can't be null!"; 

/** 
* TODO Auto-generated method documentation 
* 
* @return Long 
*/ 
public Long getId() { 
    return this.id; 
} 

/** 
* TODO Auto-generated method documentation 
* 
* @param id 
*/ 
public void setId(Long id) { 
    this.id = id; 
} 


/** 
* TODO Auto-generated method documentation 
* 
* @return Integer 
*/ 
public Integer getPrice() { 
    return this.price; 
} 

/** 
* TODO Auto-generated method documentation 
* 
* @param price 
*/ 
public void setPrice(Integer price) { 
    this.price = price; 
} 

/** 
* TODO Auto-generated method documentation 
* 
* @return String 
*/ 
public String getProductName() { 
    return this.productName; 
} 

/** 
* TODO Auto-generated method documentation 
* 
* @param productName 
*/ 
public void setProductName(String productName) { 
    this.productName = productName; 
} 

/** 
* TODO Auto-generated method documentation 
* 
* @return Order 
*/ 
public Order getOrder() { 
    return this.order; 
} 

/** 
* TODO Auto-generated method documentation 
* 
* @param Order 
*/ 
public void setOrder(Order order) { 
    this.order= order; 
} 
} 

Order.java

import java.util.Objects; 

    import javax.persistence.Entity; 
    import javax.persistence.FetchType; 
    import javax.persistence.GeneratedValue; 
    import javax.persistence.GenerationType; 
    import javax.persistence.Id; 
    import javax.persistence.OneToOne; 
    import javax.persistence.Version; 
    import javax.validation.constraints.Min; 

    import org.springframework.format.annotation.NumberFormat; 
    import org.springframework.roo.addon.javabean.annotations.RooEquals; 
    import org.springframework.roo.addon.javabean.annotations.RooJavaBean; 
    import org.springframework.roo.addon.javabean.annotations.RooToString; 
    import org.springframework.roo.addon.jpa.annotations.entity.JpaRelationType; 
    import org.springframework.roo.addon.jpa.annotations.entity.RooJpaEntity; 
    import org.springframework.roo.addon.jpa.annotations.entity.RooJpaRelation; 

    import io.springlets.format.EntityFormat; 

    /** 
    * = Order 
    * 
    * TODO Auto-generated class documentation 
    * 
    */ 
    @RooJavaBean 
    @RooToString 
    @RooJpaEntity 
    @RooEquals(isJpaEntity = true) 
    @Entity 
    @EntityFormat 
    public class Order { 

/** 
* TODO Auto-generated attribute documentation 
* 
*/ 
@Id 
@GeneratedValue(strategy = GenerationType.AUTO) 
private Long id; 

/** 
* TODO Auto-generated attribute documentation 
* 
*/ 
@Version 
private Integer version; 

/** 
* TODO Auto-generated attribute documentation 
* 
*/ 
@OneToOne(cascade = { javax.persistence.CascadeType.MERGE, 
     javax.persistence.CascadeType.PERSIST }, fetch = FetchType.LAZY, mappedBy = "order") 
@RooJpaRelation(type = JpaRelationType.AGGREGATION) 
@EntityFormat 
private Product product; 


/** 
* TODO Auto-generated attribute documentation 
* 
*/ 
public static final String ITERABLE_TO_ADD_CANT_BE_NULL_MESSAGE = "The given Iterable of items to add can't be null!"; 

/** 
* TODO Auto-generated attribute documentation 
* 
*/ 
public static final String ITERABLE_TO_REMOVE_CANT_BE_NULL_MESSAGE = "The given Iterable of items to add can't be null!"; 

/** 
* This `equals` implementation is specific for JPA entities and uses the 
* entity identifier for it, following the article in 
* https://vladmihalcea.com/2016/06/06/how-to-implement-equals-and-hashcode-using-the-jpa-entity-identifier/ 
* 
* @param obj 
* @return Boolean 
*/ 
public boolean equals(Object obj) { 
    if (this == obj) { 
     return true; 
    } 
    // instanceof is false if the instance is null 
    if (!(obj instanceof Order)) { 
     return false; 
    } 
    return getId() != null && Objects.equals(getId(), ((Order) obj).getId()); 
} 

/** 
* This `hashCode` implementation is specific for JPA entities and uses a 
* fixed `int` value to be able to identify the entity in collections after 
* a new id is assigned to the entity, following the article in 
* https://vladmihalcea.com/2016/06/06/how-to-implement-equals-and-hashcode-using-the-jpa-entity-identifier/ 
* 
* @return Integer 
*/ 
public int hashCode() { 
    return 31; 
} 

/** 
* TODO Auto-generated method documentation 
* 
* @return Long 
*/ 
public Long getId() { 
    return this.id; 
} 

/** 
* TODO Auto-generated method documentation 
* 
* @param id 
*/ 
public void setId(Long id) { 
    this.id = id; 
} 

/** 
* TODO Auto-generated method documentation 
* 
* @return Integer 
*/ 
public Integer getVersion() { 
    return this.version; 
} 

/** 
* TODO Auto-generated method documentation 
* 
* @param version 
*/ 
public void setVersion(Integer version) { 
    this.version = version; 
} 

/** 
* TODO Auto-generated method documentation 
* 
* @return Product 
*/ 
public Product getProduct() { 
    return this.product; 
} 

/** 
* TODO Auto-generated method documentation 
* 
* @param product 
*/ 
public void setProduct(Product product) { 
    this.product = product; 
} 

/** 
* TODO Auto-generated method documentation 
* 
* @param product 
*/ 
public void addToProduct(Product product) { 
    if (product == null) { 
     removeFromProduct(); 
    } else { 
     this.product = product; 
     product.setOrder(this); 
    } 
} 

/** 
* TODO Auto-generated method documentation 
* 
*/ 
public void removeFromProduct() { 
    if (this.product != null) { 
     product.setOrder(null); 
    } 
    this.product = null; 
} 
} 

回答

3

默認情況下,數據Select2DataWithConversion鍵入僅返回將被設定爲value標識符的屬性option元素以及對象(在您的情況下爲產品名稱)的表示形式爲option元素的text屬性。

這是select2組件需要構建的最小信息。

https://select2.org/data-sources/formats

然而,正如你在你的答案中描述,這是真正的共同需要在你選擇二組件的詳細信息。因此,我們重載了包含布爾參數的Select2DataWithConversion的構造函數以返回對象的全部信息。

檢查這個重載的構造在這裏:

https://github.com/DISID/springlets/blob/master/springlets-data/springlets-data-commons/src/main/java/io/springlets/data/web/select2/Select2DataWithConversion.java#L76

所以,你只需要改變你的ProductsCollectionThymeleafController。java的使用它喜歡:

Select2DataSupport<Product> select2Data = new Select2DataWithConversion<Product>(products, idExpression, getConversionService(), true); 

現在侑選擇2組件將要接收額外的信息,你需要的選項創建過程中,將其存儲在您選擇2選項的data-*屬性。要做到這一點,請使用提供select2組件的templateSelection函數。

https://select2.org/programmatic-control/retrieving-selections#using-a-jquery-selector

現在,您應該doCalculation獲得所選擇的選項,並在此之後,data-price屬性。

<script> 
    function doCalculation() { 
    var price = $('#product').find(':selected').data('price'); 
    alert("price: " + price); 
    //Do some calculation     
    } 
    doCalculation(); 
    </script> 

這就是全部!

編輯:我剛剛創建以下項目在那裏你可以找到你想要的行爲:https://github.com/jcagarcia/proofs/tree/master/select2-with-extra-info 只是檢查在以下提交必要的修改:https://github.com/jcagarcia/proofs/commit/105c18f7ad0da4d1e2089fbf71d4f27ccdb60689

希望它能幫助,

+0

獲取未定義對於價格值 – Prince

+0

由於在$('#accomidation')。find(':selected')中找不到數據。增加了console.log(price);並發現這 – Prince

+0

你如何實現'templateSelection' select2函數? – jcgarcia