2017-10-08 90 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