我正在尝试使用动态生成的列创建可编辑的数据表。
表格按原样呈现,单击时单元格进入编辑模式,但是当按下输入或焦点离开单元格时,我在服务器上得到空指针异常。调用onCellEdit
方法,但未在car对象中设置单元格值。
value
或p:inputText
的{{1}}属性的EL表达式中做了一些奇怪的事情?我应该为p:outputText
或var
上的p:dataTable
属性使用其他一些属性吗?什么样的EL表达式在这里有效?p:columns
,当它期望获得CellEditFeature.encode
但结果为空时。我使用Primefaces 4.0和5.0尝试了相同的结果。我使用的是JSF 2.2,Glassfish 4.0和Java 1.8.0_20。
如果有人能帮助我找出问题的原因,我将非常感激。在Stack Overflow上有一个动态可编辑数据表的工作示例也很有用。
Bellow是一个最小的例子,它使用了我试图添加编辑的动态生成列的Primefaces展示示例,以及异常堆栈跟踪。
网页:
CellEditor
支持bean:
<p:dataTable id="cars" var="car" value="#{dtColumnsView.cars}" widgetVar="carsTable"
editable="true" editMode="cell" >
<p:ajax event="cellEdit" listener="#{dtColumnsView.onCellEdit}" update=":form:msgs" />
<p:columns value="#{dtColumnsView.columns}" var="column" columnIndexVar="colIndex"
styleClass="ui-editable-column">
<f:facet name="header">
<h:outputText value="#{column.header}" />
</f:facet>
<p:cellEditor>
<f:facet name="output"><h:outputText value="#{car[column.property]}" /></f:facet>
<f:facet name="input"><p:inputText id="modelInput" value="#{car[column.property]}" /></f:facet>
</p:cellEditor>
</p:columns>
</p:dataTable>
异常堆栈跟踪:
@ManagedBean(name = "dtColumnsView")
@ViewScoped
public class ColumnsView implements Serializable {
private static final long serialVersionUID = 1L;
private List<ColumnModel> columns;
private List<Car> cars;
@ManagedProperty("#{carService}")
private CarService service;
@PostConstruct
public void init() {
cars = service.createCars(10);
columns = Arrays.asList(
new ColumnModel("Id", "id"),
new ColumnModel("Brand", "brand"),
new ColumnModel("Year", "year"));
}
public List<Car> getCars() {
return cars;
}
public List<String> getBrands() {
return service.getBrands();
}
public List<String> getColors() {
return service.getColors();
}
public void setService(CarService service) {
this.service = service;
}
public List<ColumnModel> getColumns() {
return columns;
}
public void onCellEdit(CellEditEvent event) {
Object oldValue = event.getOldValue();
Object newValue = event.getNewValue();
System.out.println("Cell Changed, Old: " + oldValue + ", New:" + newValue);
if (newValue != null && !newValue.equals(oldValue)) {
FacesMessage msg = new FacesMessage(FacesMessage.SEVERITY_INFO, "Cell Changed", "Old: " + oldValue + ", New:" + newValue);
FacesContext.getCurrentInstance().addMessage(null, msg);
}
}
public void dumpCars() {
for (Car c : cars) System.out.println(c.brand);
}
static public class ColumnModel implements Serializable {
private static final long serialVersionUID = 1L;
private String header;
private String property;
public ColumnModel(String header, String property) {
this.header = header;
this.property = property;
}
public String getHeader() {
return header;
}
public String getProperty() {
return property;
}
}
}
答案 0 :(得分:4)
org.primefaces.component.columns.Columns
后面的<p:columns>
类会在null
方法上返回一个硬编码的getCellEditor()
。 See source code:
258 public CellEditor getCellEditor() {
259 return null;
260 }
至少在链条中进一步解释了NPE,但由于我不是PrimeFaces开发者,我无法解释为什么它有目的地返回硬编码null
。您最好的选择是向PrimeFaces报告一个新问题。 It doesn't seem to be already reported before
同时,理论上你应该能够用<p:columns>
取代<c:forEach><p:column>
来解决这个棘手的问题。
<c:forEach items="#{dtColumnsView.columns}" var="column" varStatus="loop">
<p:column>
<f:facet name="header">
<h:outputText value="#{column.header}" />
</f:facet>
<p:cellEditor>
<f:facet name="output"><h:outputText value="#{car[column.property]}" /></f:facet>
<f:facet name="input"><p:inputText id="modelInput_#{loop.index}" value="#{car[column.property]}" /></f:facet>
</p:cellEditor>
</p:column>
</c:forEach>
注意:确保手动将迭代索引分配给循环内的任何组件ID。