Reputation: 31651
I'm dealing with an issue in the last version of Primefaces community (5.1). Using it with JSF 2.1.29 and +1000 elements brings a terrible performance issue when using Google Chrome 38 browser, either in view loading and element transfer. I'm afraid it's all about a problem in Chrome's Javascript engine. Here you've got a very basic use case:
@ManagedBean
@ViewScoped
public class PickListTestBean implements Serializable {
private DualListModel<String> values;
public PickListTestBean() {
List<String> source = new ArrayList<String>();
List<String> target = new ArrayList<String>();
for (int i = 0; i < 1000; i++) {
source.add("value" + i);
}
values = new DualListModel<String>(source, target);
}
public DualListModel<String> getValues() {
return values;
}
public void setValues(DualListModel<String> values) {
this.values = values;
}
}
And the view:
<html xmlns="http://www.w3.org/1999/xhtml"
xmlns:h="http://xmlns.jcp.org/jsf/html"
xmlns:f="http://xmlns.jcp.org/jsf/core"
xmlns:p="http://primefaces.org/ui"
xmlns:ui="http://java.sun.com/jsf/facelets">
<h:head />
<h:body>
<h:form>
<p:pickList value="#{pickListTestBean.values}" var="val"
effect="none" itemValue="#{val}" itemLabel="#{val}"
showSourceFilter="true" showTargetFilter="true">
<p:column>
#{val}
</p:column>
</p:pickList>
</h:form>
</h:body>
</html>
That's properly working in FF and IE latest versions...
Upvotes: 1
Views: 976
Reputation: 31651
Seems to be a Primefaces issue, which I opened a ticket for, but they said they were not going to fix it since there are too many elements for the component (which is true). However, there is a way to make it more efficient. The function for item generation loops appending the HTML content directly over the DOM:
generateItems: function(list, input) {
list.children('.ui-picklist-item').each(function() {
var item = $(this),
itemValue = PrimeFaces.escapeHTML(item.attr('data-item-value')),
itemLabel = item.attr('data-item-label'),
escapedItemLabel = (itemLabel) ? PrimeFaces.escapeHTML(itemLabel) : '';
input.append('<option value="' + itemValue + '" selected="selected">' + escapedItemLabel + '</option>');
});
}
Overriding the generateItems
function for the PickList
improves the perfomance noticeably:
<script>
PrimeFaces.widget.PickList.prototype.generateItems = function(b, a) {
var output = '';
b.children(".ui-picklist-item").each(function () {
var e = $(this),
f = PrimeFaces.escapeHTML(e.attr("data-item-value")),
d = e.attr("data-item-label"),
c = (d) ? PrimeFaces.escapeHTML(d) : "";
output += '<option value="' + f + '" selected="selected">' + c + "</option>";
})
a.append(output)
}
</script>
Upvotes: 1
Reputation: 1
A slight alteration to the above answer. In case you're only interested in the target selection and would like to use a large input as source you might want to use the following:
PrimeFaces.widget.PickList.prototype.generateItems = function(b, a) {
var output = '';
if(b === this.targetList) {
b.children(".ui-picklist-item").each(function () {
var e = $(this),
f = PrimeFaces.escapeHTML(e.attr("data-item-value")),
d = e.attr("data-item-label"),
c = (d) ? PrimeFaces.escapeHTML(d) : "";
output += ('<option value="' + f + '" selected="selected">' + c + '</option>');
});
}
a.append(output);
};
This will make sure processing is only performed on the (smaller) target list. As a result the DualListModel will return zero elements in the source while returning the selection as target.
Upvotes: 0