1 2 3 Previous Next 31 Replies Latest reply on May 27, 2010 4:52 AM by Igor Grinfeld

    CDK - creating a new component with action

    odelya yomtov Novice

      Hi!

       

      I am really lost in using the CDK.

       

      I need to create a component that presents days of the week: S M T W T F S

       

      the user can choose the days by clicking on the on the buttons and i will change the CSS style like in tabpanel (in or out).

       

      The value will be saved as bits: for example monday - 0100000.

       

      when the user clicks on a letter, i want to change the the value.

       

      so i created a classes inheriting from UIInput.

       

      i added on the screen the buttons:

      <input type="image" src="#{down_arrow}" styleClass="day-button" style="border:0"  />

      ..

       

      how can i set an action for each button?

       

      where do i declare the action in the java class?

       

      how do i set the value?

        • 1. Re: CDK - creating a new component with action
          Harut Sargsyan Apprentice

          Hi Odelya,

           

          Here is how to create e.g. a4j:commandButton in java class and set value, action to it...

           

          ..........

          HtmlAjaxCommandButton myButton = new HtmlAjaxCommandButton();

           

          myButton.setValue(name);
          myButton.setReRender("treetable, nodeUI, toolbar");

           

          MethodExpression actionExpression = createMethodExpression(actionName);

          myButton.setActionExpression(actionExpression);

          .......................

           

           

          private MethodExpression createMethodExpression(String actionName) {

           

                  String expression = "#{yourBean." + actionName + "}";

           

                  ELContext elContext = FacesContext.getCurrentInstance().getELContext();

           

                  MethodExpression ve = mFactory.createMethodExpression(elContext,
                          expression, String.class, new Class[0]);

           

                  return ve;

          }

          • 2. Re: CDK - creating a new component with action
            odelya yomtov Novice

            Hi Harut,

             

            Thanks.

             

            But how does it compile to CDK? i would like it to be an infra component..so the application team could work on it without programming it in the application..

             

            thanks!

            • 3. Re: CDK - creating a new component with action
              Nick Belaevski Master

              Hi Odelya,

               

              You can check this module as example: http://anonsvn.jboss.org/repos/richfaces/branches/community/3.3.X/ui/core . There are several AJAX command components there: a4j:commandLink, a4j:commandButton, a4j:jsFunction, etc - you can start investigation from any. Initial source code for the component consists of abstract UI* (e.g. UIAjaxFunction class), abstract renderer class (e.g. AjaxFunctionRendererBase), .xml file that describes component attributes (e.g. function.xml) & renderer template - .jspx (e.g. function.jspx) file. For your case you'll need to create renderer template with necessary JS code that will initiate form submit and renderer class with decode method that will handle submitted data.

               

              Another option that Harut mentioned is creation of existing components from your component and delegating all work to them (NB: CDK does not support such programming model).

              • 4. Re: CDK - creating a new component with action
                odelya yomtov Novice

                Hey Nick

                 

                I searched all day an couldn't understand which method in which class i have to overwrite to implement my method:

                what i need to do, is onclick to change the value of the component to a specific string.

                 

                thanks for your help

                • 5. Re: CDK - creating a new component with action
                  Nick Belaevski Master

                  Preparation step:

                   

                  1. Setup rendering for "onclick" handler that will submit the form either via AJAX or without it
                  For UICommand:
                  1. Queue event in decode/doDecode method
                  2. Optionally update component value in broadcast(...) method

                   

                  For UIInput:

                   

                  1. Set submittedValue in decode/doDecode method
                  • 6. Re: CDK - creating a new component with action
                    odelya yomtov Novice

                    Thanks for the reply!

                     

                    I have more questons about it:

                     

                    first- I overwrited the "broadcast" method - but the data and the focus are always became null.

                    here is the code:

                     

                    public void broadcast(FacesEvent event) throws AbortProcessingException {
                    // perform default
                    super.broadcast(event);
                    /*if (event instanceof AjaxEvent) {
                    // complete re-Render fields. AjaxEvent deliver before render response.
                    setupReRender();
                    }*/
                    if (event instanceof AjaxEvent)
                            {
                                FacesContext context = this.getFacesContext();
                                // complete re-Render fields. AjaxEvent deliver before render
                                // response.
                                this.setupReRender(context);
                                // Put data for send in response
                                Object data = this.getData();
                                AjaxContext ajaxContext = AjaxContext.getCurrentInstance(context);
                                if (null != data)
                                {
                                    ajaxContext.setResponseData(data);
                                }
                                String focus = this.getFocus();
                                if (null != focus)
                                {
                                    // search for component in tree.
                                    // XXX - use more pourful search, as in h:outputLabel
                                    // component.
                                    UIComponent focusComponent = RendererUtils.getInstance().findComponentFor(this, focus);
                                    if (null != focusComponent)
                                    {
                                        focus = focusComponent.getClientId(context);
                                    }
                                    ajaxContext.getResponseDataMap().put(FOCUS_DATA_ID, focus);
                                }
                                ajaxContext.setOncomplete(this.getOncomplete());
                               System.out.println("broadcast");
                               System.out.println(data!=null? "data: " + data.toString(): "data = null");
                               System.out.println("focus: " + focus);
                               System.out.println("FOCUS_DATA_ID: " + FOCUS_DATA_ID);
                               System.out.println("event: " + event.toString());
                            }
                    }

                     

                     

                    also - Do you have any better way to debug the the code that complied to Jar instead of printing messages?

                     

                    and also - how can I paint 7 buttons one next to the other for this component?

                     

                    Thanks a lot!

                    • 7. Re: CDK - creating a new component with action
                      Nick Belaevski Master

                      Hi,

                       

                      • You should define focus & data attributes in XML configuration file in order for them to be generated and then define values for them at example test page.
                      • We debug components using IDE built-in debugger, not by printing messages.
                      • To render 7 buttons you can use c:forEach tag in renderer template code.  
                      • 8. Re: CDK - creating a new component with action
                        odelya yomtov Novice

                        Hi Nick!

                         

                        Thanks for helping me!

                         

                        You answered me to "define focus & data attributes in XML configuration file in order for them to be generated and then define values for them at example test page" -

                         

                        I tried to follow the example of form.xml because the broadcast method I coppied it from UIAjaxForm.java and I didn't fid data & focus attributes there.

                        What do you mean? Can you focus me?

                         

                        Thank you!

                        • 9. Re: CDK - creating a new component with action
                          Ilya Shaikovsky Master

                          we have many ready-to-reuse entities for inclusions with grouped attributes.(see <3.3.X FOLDER>\cdk\generator\src\main\resources\META-INF\schema\entities\) ajax attributes added to form in XML by using

                          &ajax_component_attributes;

                          inclusion.

                          • 10. Re: CDK - creating a new component with action
                            odelya yomtov Novice

                            Hi!

                             

                            I think that maybe i didn't clarify myself.

                             

                            I am going to paint 7 buttons with c:forEach.

                             

                            I have for each one a different id. for example, day1,day2,day3,day4,day5.day6 etc.

                             

                            When the user clicks on a button, i want to get the id of the component, in order to change the submittedvalue (if for instance, the user chose day1, the submitted value will be 1).

                             

                            this is my code:

                             

                            <c:forEach var="day" items="#{this:getDaysOfWeek( component )}">
                                           <tr>
                                                <input id="#{day}" name="#{day}" type="button" value="#{day}"
                                                     onclick="#{this:getOnClick(context,component)}"
                                                     class="#{component.attributes['styleClass']}"
                                                     x:passThruWithExclusions="id,name,type,value,onclick,class">
                                                </input>
                                           </tr>
                                      </c:forEach>

                             

                            where can i refer to the button that was clicked? do i have to add actionlistener or the broadcast method can handle it?

                             

                            Message was edited by: odelya yomtov

                            • 11. Re: CDK - creating a new component with action
                              Nick Belaevski Master

                              where can i refer to the button that was clicked?

                              Submitted values for input components are assigned in decode (doDecode for RF RendererBase) method. However UIInput doesn't work with action events, so you have to add support for this by hand.

                               

                              this is my code:

                               

                              <c:forEach var="day" items="#{this:getDaysOfWeek( component )}">
                                             <tr>
                                                  <input id="#{day}" name="#{day}" type="button" value="#{day}"
                                                       onclick="#{this:getOnClick(context,component)}"
                                                       class="#{component.attributes['styleClass']}"
                                                       x:passThruWithExclusions="id,name,type,value,onclick,class">
                                                  </input>
                                             </tr>
                                        </c:forEach>

                              Two problems in he code:

                               

                              - TR requires TD children elements

                              - ID & name should be preceded with clientId, otherwise you won't be able to use more than one instance of component at the page.

                              • 12. Re: CDK - creating a new component with action
                                Igor Grinfeld Newbie

                                Hello Nick.

                                 

                                I continue the component Odelya starts with. It isn't clear how I can 'add support for this by hand'. I tried to see example of datascroller. The code is understandable, but I missed some point. the code in broadcast() is:

                                 

                                if (event instanceof DataScrollerEvent) {
                                     DataScrollerEvent dataScrollerEvent = (DataScrollerEvent) event;
                                     updateModel(dataScrollerEvent.getPage());
                                     FacesContext context = getFacesContext();
                                     MethodExpression scrollerListener = getScrollerListener();
                                     if (scrollerListener != null) {
                                          scrollerListener.invoke(context.getELContext(), new Object[]{event});
                                     }
                                }

                                 

                                 

                                and

                                 

                                public Object getOnClick(String string) {     return "Event.fire(this, 'rich:datascroller:onscroll', {'page': '" + string + "'});"; }

                                 

                                The code, as I understand it, defines that onscroll event fired when page sime number clicked' JSF creates DataScrollerEvent with pageId from parameter and broadcast called. I need to define something like that: ClickDayEvent that have day property. How I cause JSF and CDK to understand that

                                Event.fire(this, 'rich:dayselector:ondayclick', {'day': '" + string + "'}); will create ClickDayEvent and fire it?

                                 

                                Igor

                                • 13. Re: CDK - creating a new component with action
                                  Nick Belaevski Master

                                  Hi Igor,

                                   

                                  There are two things to add to the picture.

                                   

                                  First:

                                   

                                  initialize: function(clientId, submitFunction) {
                                       this.element = $(clientId);
                                       //...
                                       Event.observe(this.element, Richfaces.DatascrollerScrollEvent, submitFunction);
                                  },
                                  
                                  

                                   

                                  Event.observe(...) captures event and calls submitFunction that is passed into component constructor. That is the function that triggers Ajax request with "event" argument. Ajax function grabs page data from event argument and sends it to the server as request parameter. Here is the Java code (located in datascroller renderer) that builds this submit function:

                                   

                                       JSFunctionDefinition definition = new JSFunctionDefinition("event");
                                          
                                       JSFunction function = AjaxRendererUtils.buildAjaxFunction(component,
                                                  context);
                                          Map eventOptions = AjaxRendererUtils.buildEventOptions(context,
                                                  component, true);
                                          Map parameters = (Map) eventOptions.get("parameters");
                                          
                                          Map params = getParameters(context,component);
                                          if(!params.isEmpty()){
                                               parameters.putAll(params);
                                          }
                                          
                                          parameters.put(component.getClientId(context), new JSLiteral("event.memo.page"));
                                  

                                   

                                  Page data is stored in event as event.memo.page (that's convention of prototype.js library).

                                   

                                  Second part is easy:

                                   

                                           Map paramMap = getParamMap(context);
                                           String clientId = component.getClientId(context);
                                           String param = (String) paramMap.get(clientId);
                                           if (param != null) {
                                                UIDatascroller scroller = (UIDatascroller) component;
                                                int newPage = scroller.getPageForFacet(param);
                                                int page = scroller.getPage();
                                                if (newPage != 0 && newPage != page) {
                                                     DataScrollerEvent event = new DataScrollerEvent(scroller,
                                                               String.valueOf(page), param, newPage);
                                                     event.queue();
                                  
                                                }
                                  

                                  Submitted parameter value is read from request and queued with event.

                                   

                                  For more "clean" approach that doesn't use prototype.js I still suggest to look at code for a4j:commandLink component.

                                  • 14. Re: CDK - creating a new component with action
                                    odelya yomtov Novice

                                    Thank you Nick.

                                    However I'm new in richFaces, so something isn't clear for me. I don't see in Java code name of submitFunction. How renderer can know that ajax function you build is same submitFunction that you've defined in javascript prototype. May be it isn't same function? If it is not the same, how I define it. Is such example exists in datascroller.js or commandlink.js?

                                     

                                    Igor.

                                    1 2 3 Previous Next