问题
I have a custom JSF component renderer that renders pagination component for datatables, but it hasn't ajax behavior . I learned that it could be done by inserting ajax to encode method or by making support of f ajax tag. Unfortunately I'm not very familiar with ajax, so could you please tell me how I should modify this code to make it ajaxable?
@FacesRenderer(componentFamily="javax.faces.Command",
rendererType="com.component.Pager")
public class PagerRenderer extends Renderer {
private static final int SHOW_PAGES = 3;
private static final String HIDDEN_FIELD_ID ="tableFormPaginatorInput";
public void encodeBegin(FacesContext context, UIComponent component)
throws IOException {
ClientBehaviorContext behaviorContext =
ClientBehaviorContext.createClientBehaviorContext(context,
component, "click", component.getClientId(context), null);
String id = component.getClientId(context);
UIComponent parent = component;
while (!(parent instanceof UIForm)) parent = parent.getParent();
String formId = parent.getClientId(context);
ResponseWriter writer = context.getResponseWriter();
writer.startElement("div", component);
writer.writeAttribute("class", "paginator-section", null);
String styleClass = (String) component.getAttributes().get("styleClass");
String selectedStyleClass
= (String) component.getAttributes().get("selectedStyleClass");
String dataTableId = (String) component.getAttributes().get("dataTableId");
// find the component with the given ID
UIData data = (UIData) component.findComponent(dataTableId);
int first = data.getFirst();
int itemcount = data.getRowCount();
int pagesize = data.getRows();
if (pagesize <= 0) pagesize = itemcount;
int pages = itemcount / pagesize;
if (itemcount % pagesize != 0) pages++;
int currentPage = first / pagesize;
if (first >= itemcount - pagesize) currentPage = pages - 1;
int startPage = 0;
int endPage = pages;
if (SHOW_PAGES > 0) {
startPage = (currentPage / SHOW_PAGES ) * SHOW_PAGES ;
endPage = Math.min(startPage + SHOW_PAGES , pages);
}
if (currentPage > 0)
writeLink(writer, component, formId, id, "<", styleClass);
if (startPage > 0)
writeLink(writer, component, formId, id, "..", styleClass);
for (int i = startPage; i < endPage; i++) {
writeLink(writer, component, formId, id, "" + (i + 1),
i == currentPage ? selectedStyleClass : styleClass);
}
if (endPage < pages)
writeLink(writer, component, formId, id, "...", styleClass);
if (first < itemcount - pagesize)
writeLink(writer, component, formId, id, ">", styleClass);
/* CommandButton commandButton = new CommandButton();
commandButton.setValue(currentPage);
commandButton.setUpdate("");
commandButton.setAjax(true);
commandButton.addActionListener(new MyActionListener());
commandButton.encodeAll(context);*/
writer.endElement("div");
// hidden field to hold result
writeHiddenField(writer, component, id);
}
private void writeLink(ResponseWriter writer, UIComponent component,
String formId, String id, String value, String styleClass)
throws IOException {
writer.writeText(" ", null);
writer.startElement("a", component);
writer.writeAttribute("href", "#", null);
writer.writeAttribute("onclick", onclickCode(formId, id, value) , null);
if (styleClass != null)
writer.writeAttribute("class", styleClass, "styleClass");
writer.writeText(value, null);
writer.endElement("a");
}
private void writeLink1(ResponseWriter writer, UIComponent component,
String formId, String id, String value, String styleClass)
throws IOException {
writer.writeText(" ", null);
writer.startElement("a", component);
writer.writeAttribute("href", "#", null);
writer.writeAttribute("data-tableFormPaginator", value, null);
if (styleClass != null)
writer.writeAttribute("class", styleClass, "styleClass");
writer.writeText(value, null);
writer.endElement("a");
}
private String onclickCode(String formId, String id, String value) {
return new StringBuilder().append("document.forms['")
.append(formId).append("']['")
.append(id).append("'].value='").append(value).append("'; document.forms['")
.append(formId).append("'].submit(); return false;").toString();
}
private String onclickCodewithout(String formId, String id, String value,UIComponent component) {
return "jsf.ajax.request('" + component.getClientId() +
"', null, {'render': '" +
component.getParent().getClientId() + "',"+id+":"+value+" })";
}
private void writeHiddenField(ResponseWriter writer, UIComponent component,
String id) throws IOException {
writer.startElement("input", component);
writer.writeAttribute("id", HIDDEN_FIELD_ID, null);
writer.writeAttribute("class", "paginator-input-value", null);
writer.writeAttribute("type", "hidden", null);
writer.writeAttribute("name", id, null);
writer.endElement("input");
}
public void decode(FacesContext context, UIComponent component) {
String id = component.getClientId(context);
Map<String, String> parameters
= context.getExternalContext().getRequestParameterMap();
String response = (String) parameters.get(id);
if (response == null || response.equals("")) return;
String dataTableId = (String) component.getAttributes().get("dataTableId");
int showpages = SHOW_PAGES ;//toInt(component.getAttributes().get("showpages"));
UIData data = (UIData) component.findComponent(dataTableId);
int first = data.getFirst();
int itemcount = data.getRowCount();
int pagesize = data.getRows();
if (pagesize <= 0) pagesize = itemcount;
if (response.equals("<")) first -= pagesize;
else if (response.equals(">")) first += pagesize;
else if (response.equals("..")) first -= pagesize * showpages;
else if (response.equals("...")) first += pagesize * showpages;
else {
int page = Integer.parseInt(response);
first = (page - 1) * pagesize;
}
if (first + pagesize > itemcount) first = itemcount - pagesize;
if (first < 0) first = 0;
data.setFirst(first);
}
private static int toInt(Object value) {
if (value == null) return 0;
if (value instanceof Number) return ((Number) value).intValue();
if (value instanceof String) return Integer.parseInt((String) value);
throw new IllegalArgumentException("Cannot convert " + value);
}
回答1:
f:ajax
tag can only be directly nested in an UIComponent which implements the ClientBehaviorHolder interface.
I saw that you try to implement onclick for your table, if you are using Mojarra, then it has utils method that you help you render onclick behavior that will work with f:ajax as well
renderSelectOnclick
http://grepcode.com/file/repo1.maven.org/maven2/com.sun.faces/jsf-impl/2.1.19/com/sun/faces/renderkit/RenderKitUtils.java#RenderKitUtils.renderSelectOnclick%28com.sun.faces.renderkit.FacesContext%2Cjavax.faces.component.UIComponent%2Cboolean%29
You can use it inside your encode method
来源:https://stackoverflow.com/questions/17659287/add-ajax-behaviour-to-jsf-renderer