This isn't possible with a standard <p:selectManyCheckbox>
, at least not with this kind of dynamics. If it were static values, you could just have used the CSS3 nth-child()
selector for this. With dynamic values in a <p:selectManyCheckbox>
, you'd basically need to override its renderer (which is not a trivial job) or to post a feature request (which might take longer than you want).
Your best bet is using <ui:repeat>
or <h:dataTable>
instead wherein you render a single <p:selectBooleanCheckbox>
on a per-row basis. This allows you specifying a styleClass
on a per-checkbox basis. This only also requires a technical change in how the selectedMovies
property is populated.
Here's a concrete kickoff example with <h:dataTable>
(note: the <p:selectManyCheckbox>
itself also generates a <table>
, so layout-technically there's not so much difference, you can always choose for <ui:repeat>
if the table bothers you semantically):
<h:dataTable value="#{bean.movies}" var="movie" styleClass="ui-selectmanycheckbox ui-widget">
<h:column>
<p:selectBooleanCheckbox id="checkbox" converter="javax.faces.Boolean"
value="#{bean.checkedMovieIds[movie.id]}" styleClass="#{movie.type}" />
</h:column>
<h:column>
<p:outputLabel for="checkbox" value="#{movie.title}" />
</h:column>
</h:dataTable>
<p:commandButton value="Submit" actionListener="#{bean.collectMovies}" action="#{bean.submit}" />
Notes:
- The
<h:dataTable styleClass>
uses exactly the same CSS as <p:selectManyCheckbox>
, so the checkbox table look'n'feel is exactly the same.
- The
converter="javax.faces.Boolean"
is (actually, to my surprise) mandatory, because it would otherwise set checked values true
and false
as String
instead of Boolean
; this problem doesn't exist in <h:selectBooleanCheckbox>
, perhaps a PF bug?
- The
styleClass="#{movie.type}"
made in this particular use case more sense than styleClass="#{movie.id}"
, because it seems a ridiculuous task to specify a separate style class for every individual "id" value which usually represents an unique auto-assigned DB identifier; you can always change it in your actual code if you want.
- The
actionListener
does the job of collecting the selectedMovies
before the actual action
method. You can of course also do the job in the actual action
method, but this it's then not so cleanly separated anymore.
The backing bean look like this (the checkedMovieIds
assumes that Movie
has a Long id
property):
private List<Movie> movies;
private Map<Long, Boolean> checkedMovieIds;
private List<Movie> selectedMovies;
@PostConstruct
public void init() {
movies = populateItSomehow();
checkedMovieIds = new HashMap<Long, Boolean>();
}
public void collectMovies(ActionEvent event) {
selectedMovies = new ArrayList<Movie>();
for (Movie movie : movies) {
if (checkedMovieIds.get(movie.getId())) {
selectedMovies.add(movie);
}
}
}
public void submit() {
System.out.println(selectedMovies);
// ...
}
// +getters (note: no setters necessary for all those three properties)
Assuming that #{movie.type}
can have the values action
, comedy
, fantasy
and horror
(it's by the way a perfect enum
type candidate), then you can style the individual checkboxes as follows:
.action .ui-chkbox-box {
background-color: red;
}
.comedy .ui-chkbox-box {
background-color: orange;
}
.fantasy .ui-chkbox-box {
background-color: green;
}
.horror .ui-chkbox-box {
background-color: blue;
}