I've become stuck on this one:
<rich:dataTable id="tabA" value="#{m.a}" rowKeyVar="nr" var="ex">
<rich:column><h:outputText value="Exercise #{nr + 1}:" /></rich:column>
<rich:column><h:inputText value="#{ex}" /></rich:column>
</rich:dataTable>
<h:panelGrid columns="2">
<a4j:commandButton value="+" title="new" ajaxSingle="true"
action="#{m.createNewExercise}" reRender="tabA"/>
<a4j:commandButton value="-" title="remove last" ajaxSingle="true"
action="#{m.deleteExercise}" reRender="tabA"/>
</h:panelGrid>
Because this is part of a bigger form, I have set ajaxSingle="true"
.
The value I'm iterating over is a List of Strings, defined like this:
@Entity
public class M {
...
private List<String> a = Lists.newArrayList();
@CollectionOfElements
public List<String> getA() { return a; }
public void setA(List<String> a) { this.a = a; }
}
This fails to update the backing list a
when submitted (submit is done via a simple <h:commandButton>
). Since the content from the inputText
elements is submitted, JSF seems failing to apply the values. Maybe someone can shed light on whether this is because of the @CollectionOfElements
storage type in M
.
So what I'm looking for is a way to save the ex
values when calling createNewExercise
or deleteExercise
, either by not having to reRender the complete table or by sending them to the server first.
I can probably make it work via a binding like suggested here, but I'm interested in a way to avoid the overhead of a binding.
The problem is the ajaxSingle="true"
attribute, combined with JSF's apparent inability to update a @CollectionOfElements
.
The description of ajaxSingle
clearly states that it skips all model updates not belonging to it's component (which is not the dataTable nor it's value attribute). So this is classic PEBKAC.
But this still doesn't work w/o ajaxSingle, which led me to believe the JSF side was OK when I was testing that option.
What I ended up with was:
<rich:dataTable id="tabA" value="#{m.a}" rowKeyVar="nr" var="ex">
<rich:column><h:outputText value="Exercise #{nr + 1}:" /></rich:column>
<rich:column><h:inputText value="#{ex}" /></rich:column>
</rich:dataTable>
<h:panelGrid columns="2">
<a4j:commandButton value="+" title="new"
action="#{m.createNewExercise}" reRender="tabA"/>
<a4j:commandButton value="-" title="remove last"
action="#{m.deleteExercise}" reRender="tabA"/>
</h:panelGrid>
And the Beans:
@Entity
public class M {
...
private List<Exercise> a = Lists.newArrayList();
@OneToMany(cascade = CascadeType.ALL)
@JoinColumn(name = "ex_id")
public List<Exercise> getA() { return a; }
public void setA(List<Exercise> a) { this.a = a; }
}
@Entity
public class Exercise {
[id definition omitted]
private M m;
private String description;
@ManyToOne
@JoinColumn(name = "ex_id", insertable = false, updatable =false)
public M getM() { return m; }
public void setM(M m) { this.m = m; }
public String getDescription() { return description; }
public void setDescription(String d) { this.description = d; }
}