It is possible to do everything you want.
You can build something close to what you want using existing controls. A good way to get the most out of JSF is to tailor the model for the view. For example, this view displays edit options that allow you to add values to a data table.
<f:view>
<h:form>
<h:dataTable value="#{people.list}" var="row">
<h:column>
<f:facet name="header">
<h:outputText value="#" />
</f:facet>
<h:selectBooleanCheckbox value="#{row.selected}" />
</h:column>
<h:column>
<f:facet name="header">
<h:outputText value="First Name" />
</f:facet>
<h:inputText value="#{row.firstname}" />
</h:column>
<h:column>
<f:facet name="header">
<h:outputText value="Last Name" />
</f:facet>
<h:inputText value="#{row.lastname}" />
</h:column>
<f:facet name="footer">
<h:panelGroup>
<h:commandButton value="Add Row" action="#{people.addPerson}" />
<h:commandButton value="Delete Selected"
action="#{people.deleteSelected}" />
<h:commandButton value="Finish" action="#{people.finish}" />
</h:panelGroup>
</f:facet>
</h:dataTable>
</h:form>
</f:view>
People bean:
public class People implements Serializable {
private static final long serialVersionUID = 1L;
private List<Person> people = new ArrayList<Person>();
public People() {
// initialise with one entry
people.add(new Person());
}
public List<Person> getList() {
return people;
}
public String addPerson() {
people.add(new Person());
return null;
}
public String deleteSelected() {
Iterator<Person> entries = people.iterator();
while (entries.hasNext()) {
Person person = entries.next();
if (person.isSelected()) {
entries.remove();
}
}
return null;
}
public String finish() {
System.out.println(people);
return "someNavigationRule";
}
}
Person bean:
public class Person implements Serializable {
private static final long serialVersionUID = 1L;
private String firstname;
private String lastname;
private transient boolean selected = false;
public String getFirstname() {
return firstname;
}
public void setFirstname(String firstname) {
this.firstname = firstname;
}
public String getLastname() {
return lastname;
}
public void setLastname(String lastname) {
this.lastname = lastname;
}
public boolean isSelected() {
return selected;
}
public void setSelected(boolean selected) {
this.selected = selected;
}
}
faces-config.xml:
<managed-bean>
<managed-bean-name>people</managed-bean-name>
<managed-bean-class>addmultiple.People</managed-bean-class>
<managed-bean-scope>session</managed-bean-scope>
</managed-bean>
This approach is quite flexible and with some CSS, can look quite good. With a few changes to the view and model, you can have only the last row editable, for example.
If the resultant experience isn't rich enough or if you need something you can reuse, you can create a custom control. It is difficult to get into the specifics without knowing exactly what you want, but you probably would need:
- A new Renderer for emitting HTML and decoding form requests.
- (Maybe) a new component, probably extending UIData, and a concrete form for exposing renderkit-specific (e.g. HTML) attributes.
- A new JSP tag class for allowing the control to be used in JSPs.
- Definitions for all of the above in a faces-config.xml (see spec).