3 Replies Latest reply on Jun 17, 2009 5:44 AM by marchewk

    Custom component - Pivot Table

      Hi.

      I want to write custom component that shows in my application an Pivot Table with links in header such as Down, Up etc...

      I dont want to use CDK, because this component is too complicated to write it with any template.

      I write already component, tag and renderer class and configure them in eclipse project. My component works as simple JSF component and writes to output html table, but I dont know how can I write link to raise custom events.

      What should I do to enable Ajax events for custom component?

      Can someone send me any custom component with custom events, that would be base for my component?

      My code is below:



      DataSubgroupRenderer:

      
      package bdr.components;
      
      import java.io.IOException;
      import java.util.Map;
      
      import javax.faces.component.UIComponent;
      import javax.faces.context.FacesContext;
      import javax.faces.context.ResponseWriter;
      import javax.faces.render.Renderer;
      
      public class DataSubgroupRenderer extends Renderer {
      
       @SuppressWarnings("unchecked")
       @Override
       public void decode(FacesContext context, UIComponent component) {
       //super.decode(context, component);
       Map requestMap = context.getExternalContext().getRequestParameterMap();
       String clientId = component.getClientId(context);
       UIDataSubgroup dsComp = (UIDataSubgroup)component;
       try {
       if (requestMap.get(clientId+ ".vertical")!=null) {
       dsComp.setHorizontal(false);
       } else if (requestMap.get(clientId+ ".horizontal")!=null) {
       dsComp.setHorizontal(true);
       }
       dsComp.setValid(true);
       } catch (NumberFormatException ex) {
       dsComp.setSubmittedValue((String) requestMap.get(clientId));
       }
       }
      
       @Override
       public void encodeBegin(FacesContext context, UIComponent component)
       throws IOException {
       //super(context, component);
       ResponseWriter writer = context.getResponseWriter();
       String clientId = component.getClientId(context);
       UIDataSubgroup dsComp = (UIDataSubgroup)component;
      
       //generate buttons
       if (dsComp.isHorizontal()) {
       writer.startElement("input", dsComp);
       writer.writeAttribute("type", "Submit", null);
       writer.writeAttribute("name", clientId+".vertical", "clientId");
       writer.writeAttribute("value", "Goto Vertical", null);
       writer.endElement("input");
       } else {
       writer.startElement("input", dsComp);
       writer.writeAttribute("type", "Submit", null);
       writer.writeAttribute("name", clientId+".horizontal", "clientId");
       writer.writeAttribute("value", "Goto Horizontal", null);
       writer.endElement("input");
       }
      
       //generate table
       if (dsComp.isHorizontal()) {
       writer.write("<table border='1' cellspacing='0' cellpadding='0'>");
       for (int i=0;i<Integer.valueOf(dsComp.getRows()).intValue();i++) {
       writer.write("<tr>");
       for (int j=0;j<Integer.valueOf(dsComp.getColumns()).intValue();j++) {
       writer.write("<td>"+i+","+j+"</td>");
       }
       writer.write("</tr>");
       }
       writer.write("</table>");
       } else {
       writer.write("<table border='1' cellspacing='0' cellpadding='0'>");
       for (int i=0;i<Integer.valueOf(dsComp.getColumns()).intValue();i++) {
       writer.write("<tr>");
       for (int j=0;j<Integer.valueOf(dsComp.getRows()).intValue();j++) {
       writer.write("<td>"+i+","+j+"</td>");
       }
       writer.write("</tr>");
       }
       writer.write("</table>");
       }
      
       }
      
      }
      
      




      DataSubgroupTag:

      package bdr.components;
      
      import javax.el.ValueExpression;
      import javax.faces.component.UIComponent;
      import javax.faces.context.FacesContext;
      import javax.faces.webapp.UIComponentELTag;
      
      public class DataSubgroupTag extends UIComponentELTag {
      
       public ValueExpression rows;
       public ValueExpression columns;
      
       @Override
       public String getComponentType() {
       return UIDataSubgroup.COMPONENT_TYPE;
       }
      
       @Override
       public String getRendererType() {
       return UIDataSubgroup.RENDERER_TYPE;
       }
      
       @Override
       protected void setProperties(UIComponent component) {
       super.setProperties(component);
       UIDataSubgroup dsComp = null;
       try {
       dsComp = (UIDataSubgroup)component;
       } catch (ClassCastException ex) {
       throw new IllegalStateException("Component: "+component.toString()+" not expected type. Expected bdr.components.UIDataSubgroup.");
       }
       if (rows != null) {
       component.setValueExpression("rows", this.rows);
       }
       if (columns != null) {
       component.setValueExpression("columns", this.columns);
       }
       }
      
       public void release() {
       super.release();
       rows = null;
       columns = null;
       }
      
       public ValueExpression getRows() {
       return rows;
       }
      
       public void setRows(ValueExpression rows) {
       this.rows = rows;
       }
      
       public ValueExpression getColumns() {
       return columns;
       }
      
       public void setColumns(ValueExpression columns) {
       this.columns = columns;
       }
      
      }
      
      




      UIDataSubgroup:

      package bdr.components;
      
      import javax.el.ValueExpression;
      import javax.faces.component.UIInput;
      import javax.faces.context.FacesContext;
      
      public class UIDataSubgroup extends UIInput {
       public static final String COMPONENT_TYPE = "bdr.components.DataSubgroup";
       public static final String RENDERER_TYPE = "bdr.components.DataSubgroupRenderer";
      
       private boolean horizontal = true;
       private Integer rows;
       private Integer columns;
      
       public UIDataSubgroup() {
       setRendererType(RENDERER_TYPE);
       this.horizontal = true;
       }
      
       @Override
       public String getFamily() {
       return COMPONENT_TYPE;
       }
      
       public boolean isHorizontal() {
       return horizontal;
       }
      
       public void setHorizontal(boolean horizontal) {
       this.horizontal = horizontal;
       }
      
       public Integer getRows() {
       if (null!=this.rows) {
       return this.rows;
       }
       ValueExpression _ve = getValueExpression("rows");
       Object val = _ve.getValue(getFacesContext().getELContext());
       return (_ve!=null)?(Integer)_ve.getValue(getFacesContext().getELContext()):null;
       }
      
       public void setRows(Integer rows) {
       this.rows = rows;
       }
      
       public Integer getColumns() {
       if (null!=this.columns) {
       return this.columns;
       }
       ValueExpression _ve = getValueExpression("columns");
       return (_ve!=null)?(Integer)_ve.getValue(getFacesContext().getELContext()):null;
       }
      
       public void setColumns(Integer columns) {
       this.columns = columns;
       }
      
       @Override
       public void restoreState(FacesContext context, Object state) {
       Object values[] = (Object[]) state;
       super.restoreState(context, values[0]);
       if (((String)values[1]).equals("H"))
       this.horizontal = true;
       else
       this.horizontal = false;
       this.rows = (Integer)values[2];
       this.columns = (Integer)values[3];
       }
      
       @Override
       public Object saveState(FacesContext context) {
       Object values[] = new Object[4];
       values[0] = super.saveState(context);
       if (this.horizontal)
       values[1] = "H";
       else
       values[1] = "V";
       values[2] = this.rows;
       values[3] = this.columns;
       return values;
       }
      
      
      }
      
      



      bdr-components-taglib.xml
      <taglib xmlns="http://java.sun.com/xml/ns/javaee"
       xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
       xsi:schemaLocation="http://java.sun.com/xml/ns/javaee
       http://java.sun.com/xml/ns/javaee/web-jsptaglibrary_2_1.xsd"
       version="2.1">
      
       <tlib-version>1.0</tlib-version>
       <short-name>bdr-components-taglib</short-name>
       <uri>bdr-components-taglib</uri>
      
       <tag>
       <name>dataSubgroup</name>
       <tag-class>bdr.components.DataSubgroupTag</tag-class>
      
       <attribute>
       <name>binding</name>
       <description>
       A value binding that points to a bean property
       </description>
       </attribute>
      
       <attribute>
       <name>id</name>
       <description>The client id of this component</description>
       </attribute>
      
       <attribute>
       <name>rendered</name>
       <description>Is this component rendered?</description>
       </attribute>
      
       <attribute>
       <name>rows</name>
       <description>Is this component rendered?</description>
       <rtexprvalue>true</rtexprvalue>
       <deferred-value><type>java.lang.Object</type></deferred-value>
       </attribute>
      
       <attribute>
       <name>columns</name>
       <description>Is this component rendered?</description>
       <rtexprvalue>true</rtexprvalue>
       <deferred-value><type>java.lang.Object</type></deferred-value>
       </attribute>
      
       </tag>
      
      </taglib>
      
      



      faces-config.xml
      <?xml version="1.0" encoding="UTF-8"?>
      
      <faces-config
       xmlns="http://java.sun.com/xml/ns/javaee"
       xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
       xsi:schemaLocation="http://java.sun.com/xml/ns/javaee http://java.sun.com/xml/ns/javaee/web-facesconfig_1_2.xsd"
       version="1.2">
      
       <application>
       <message-bundle>resources.application</message-bundle>
       <locale-config>
       <default-locale>en</default-locale>
       <supported-locale>pl</supported-locale>
       <supported-locale>en</supported-locale>
       </locale-config>
       </application>
      
       <component>
       <component-type>bdr.components.DataSubgroup</component-type>
       <component-class>bdr.components.UIDataSubgroup</component-class>
       <component-extension>
       <renderer-type>bdr.components.DataSubgroupRenderer</renderer-type>
       </component-extension>
       </component>
       <render-kit>
       <description>Renderkit implementation for the DataSubgroup component</description>
       <renderer>
       <component-family>bdr.components.DataSubgroup</component-family>
       <renderer-type>bdr.components.DataSubgroupRenderer</renderer-type>
       <renderer-class>bdr.components.DataSubgroupRenderer</renderer-class>
       </renderer>
       </render-kit>
       <managed-bean>
       <managed-bean-name>dataSubgrBean</managed-bean-name>
       <managed-bean-class>bdr.beans.DataSubgroupBean</managed-bean-class>
       <managed-bean-scope>session</managed-bean-scope>
       </managed-bean>
       </faces-config>
      
      


      Please help me. Thanks.

      SM

        • 1. Re: Custom component - Pivot Table
          nbelaevski

          Hi SM,

          Check org.ajax4jsf.renderkit.AjaxCommandRendererBase class. BTW,

          writer.write("<table border='1' cellspacing='0' cellpadding='0'>");
          does not seem correct way to write markup. I guess, it's only for testing?

          • 2. Re: Custom component - Pivot Table

             

            "nbelaevski" wrote:

            BTW,
            writer.write("<table border='1' cellspacing='0' cellpadding='0'>");
            does not seem correct way to write markup. I guess, it's only for testing?


            Table is very complicated and huge, so I write like this. Why this is not correct way to write markup? How should I write this?

            Thanks for help.

            SM

            • 3. Re: Custom component - Pivot Table

              I write renderer class like this:

              package bdr.components;
              
              import java.io.IOException;
              import java.util.Map;
              
              import javax.faces.component.UIComponent;
              import javax.faces.context.FacesContext;
              import javax.faces.context.ResponseWriter;
              import javax.faces.render.Renderer;
              
              import org.ajax4jsf.javascript.JSFunction;
              import org.ajax4jsf.renderkit.AjaxCommandRendererBase;
              import org.ajax4jsf.renderkit.AjaxRendererUtils;
              import org.ajax4jsf.renderkit.ComponentVariables;
              import org.ajax4jsf.renderkit.ComponentsVariableResolver;
              
              public class DataSubgroupRenderer extends AjaxCommandRendererBase
              {
              
               public DataSubgroupRenderer() {
               super();
               }
              
               @SuppressWarnings("unchecked")
               @Override
               public void doDecode(FacesContext context, UIComponent component) {
               Map requestMap = context.getExternalContext().getRequestParameterMap();
               String clientId = component.getClientId(context);
               UIDataSubgroup dsComp = (UIDataSubgroup)component;
               System.out.println("----------------------");
               try {
               if (requestMap.get(clientId+ "_layout")!=null && requestMap.get(clientId+"_layout").equals("VERTICAL")) {
               System.out.println("dsComp.isHorizontal()="+dsComp.isHorizontal()+", dsComp.setHorizontal(false)");
               dsComp.setHorizontal(false);
               } else if (requestMap.get(clientId+ "_layout")!=null && requestMap.get(clientId+"_layout").equals("HORIZONTAL")) {
               System.out.println("dsComp.isHorizontal()="+dsComp.isHorizontal()+", dsComp.setHorizontal(true)");
               dsComp.setHorizontal(true);
               }
               dsComp.setValid(true);
               } catch (NumberFormatException ex) {
               dsComp.setSubmittedValue((String) requestMap.get(clientId));
               }
               }
              
               protected void doEncodeEnd(ResponseWriter writer, FacesContext context, UIDataSubgroup component, ComponentVariables variables) throws IOException {
              
               java.lang.String clientId = component.getClientId(context);
              
               writer.startElement("div", component);
               getUtils().writeAttribute(writer, "id", clientId );
              
               // pass thru attributes
               getUtils().encodeAttributesFromArray(context,component,new String[] {
               "align" ,
               "dir" ,
               "lang" ,
               "onclick" ,
               "ondblclick" ,
               "onkeydown" ,
               "onkeypress" ,
               "onkeyup" ,
               "onmousedown" ,
               "onmousemove" ,
               "onmouseout" ,
               "onmouseover" ,
               "onmouseup" ,
               "style" ,
               "title" ,
               "xml:lang" });
              
               UIDataSubgroup dsComp = (UIDataSubgroup)component;
               System.out.println("doEncodeEnd: dsComp.IsHorizontal = "+dsComp.isHorizontal());
              
               JSFunction ajaxFunction = AjaxRendererUtils.buildAjaxFunction(dsComp, context);
               Map<String, Object> eventOptions = AjaxRendererUtils.buildEventOptions(context, dsComp);
              
               @SuppressWarnings("unchecked")
              
               //generate buttons
               //if (dsComp.isHorizontal()) {
               Map<String, Object> parameters = (Map<String, Object>) eventOptions.get("parameters");
               StringBuffer buffer = new StringBuffer();
               parameters.put(clientId+"_layout","VERTICAL");
               ajaxFunction.addParameter(eventOptions);
               ajaxFunction.appendScript(buffer);
              
               writer.startElement("input", dsComp);
               writer.writeAttribute("type", "button", null);
               writer.writeAttribute("name", clientId+"_layout", "VERTICAL");
               writer.writeAttribute("value", "Goto Vertical", null);
               writer.writeAttribute("onclick", buffer.toString(), null);
               writer.endElement("input");
               //} else {
               parameters = (Map<String, Object>) eventOptions.get("parameters");
               buffer = new StringBuffer();
               parameters.put(clientId+"_layout","HORIZONTAL");
               ajaxFunction.addParameter(eventOptions);
               ajaxFunction.appendScript(buffer);
              
               writer.startElement("input", dsComp);
               writer.writeAttribute("type", "button", null);
               writer.writeAttribute("name", clientId+"_layout", "HORIZONTAL");
               writer.writeAttribute("value", "Goto Horizontal", null);
               writer.writeAttribute("onclick", buffer.toString(), null);
               writer.endElement("input");
               //}
              
               //generate table
               if (dsComp.isHorizontal()) {
               writer.write("<table border='1' cellspacing='0' cellpadding='0'>");
               for (int i=0;i<Integer.valueOf(dsComp.getRows()).intValue();i++) {
               writer.write("<tr>");
               for (int j=0;j<Integer.valueOf(dsComp.getColumns()).intValue();j++) {
               writer.write("<td>"+i+","+j+"</td>");
               }
               writer.write("</tr>");
               }
               writer.write("</table>");
               } else {
               writer.write("<table border='1' cellspacing='0' cellpadding='0'>");
               for (int i=0;i<Integer.valueOf(dsComp.getColumns()).intValue();i++) {
               writer.write("<tr>");
               for (int j=0;j<Integer.valueOf(dsComp.getRows()).intValue();j++) {
               writer.write("<td>"+i+","+j+"</td>");
               }
               writer.write("</tr>");
               }
               writer.write("</table>");
               }
              
               //writer.startElement("h1", component);
               //writer.writeText(new java.util.Date().toString(),null);
               //writer.endElement("h1");
              
               writer.endElement("div");
               }
              
              
               @Override
               protected void doEncodeEnd(ResponseWriter writer, FacesContext context, UIComponent component) throws IOException {
               ComponentVariables variables = ComponentsVariableResolver.getVariables(this, component);
               System.out.println("doEncodeEnd: variables = "+variables.toString());
               doEncodeEnd(writer, context, (UIDataSubgroup)component, variables );
               ComponentsVariableResolver.removeVariables(this, component);
               }
              
              
               @Override
               protected Class<? extends UIComponent> getComponentClass() {
               return UIDataSubgroup.class;
               }
              
              }
              
              


              Now I have html table and 2 buttons that sends Ajax requests. When I click on these buttons, I have on the output console such messages:
              ----------------------
              dsComp.isHorizontal()=true, dsComp.setHorizontal(false)
              ----------------------
              dsComp.isHorizontal()=false, dsComp.setHorizontal(true)
              ----------------------
              dsComp.isHorizontal()=true, dsComp.setHorizontal(false)
              ----------------------
              dsComp.isHorizontal()=false, dsComp.setHorizontal(true)
              


              That means Ajax requests are properly decoded and state for the component is set for good values, but component view on the html page is not refreshed and method "doEncodeEnd" of the rendered is not called.

              How to repair this, to refresh component view on the page?

              Please help me, because in out work i try to learn richfaces to use it in our project, but we must write few own components.

              Thanks and sorry for my english, which is not so good as it should be.