5

I am developing a JSF Custom Component, using the information I found on the following book Pro JSF and HTML5 by Apress.

So far, I successfully developed:

  • the java class to obtain the data to be rendered in the component
  • the java component class
  • the java renderer class
  • the taglib file
  • an example page to render the taglib

Everything is working fine, the component is successfully rendered.

Now I would like to add javascript events and behaviour to the rendered elements, more specifically, the purpose of my custom component is to render a menu on a web page, and I would like to ad a dropdown effects to the menu entry. I know how to code the whole thing, in JavaScript, what I don't know is:

What is the best practice to add javascript events and behaviour to the element rendered within a custom component?

Where should the JS files be placed? How do I bind the events to the elements? Is it done in the render class, or after, on the web pages?

Thanks, I'm willing to provide more specific information about my code, if required.


Java Component Class

Note: The CosmoMenu class is just a bean. It basically stores a menu tree (a label, an id and a set of children, if any).

package components;

import com.google.gson.Gson;
import com.google.gson.JsonElement;
import com.google.gson.JsonParser;
import domain.CosmoMenu;
import javax.faces.component.FacesComponent;
import javax.faces.component.UIComponentBase;


@FacesComponent(CosmoMenuComponent.COMPONENT_TYPE)
public class CosmoMenuComponent extends UIComponentBase{

  /** Component family of {@link CosmoMenuComponent}.        */
  public static final String COMPONENT_FAMILY = "CosmoMenu";

  /** Component type of {@link CosmoMenuComponent}.          */ 
  public static final String COMPONENT_TYPE = "CosmoMenu";    

  @Override
  public String getFamily(){
      return CosmoMenuComponent.COMPONENT_FAMILY;
  }


  private CosmoMenu theMenu;    

  public CosmoMenu getMenu(){

      Gson gson = new Gson();
      JsonParser jsonParser = new JsonParser();
      CosmoMenuAPI myApi = new CosmoMenuAPI();

      String strMenu = myApi.getMenu();
      JsonElement jEl = jsonParser.parse(strMenu);

      theMenu = gson.fromJson(jEl, CosmoMenu.class);
      return theMenu;      
  }
}
Josef E.
  • 2,179
  • 4
  • 15
  • 30
INElutTabile
  • 866
  • 2
  • 20
  • 38

2 Answers2

1

If you want your components to be reusable, I encourage you to pack everything in an independent jar. If using Servlet 3.0, you'll be able to easily access the web resources putting them in META-INF/resources. Provide the jar a faces-config.xml and you'll make it JSF annotation scannable:

components
    \-(Your cource code)
META-INF 
    \-faces-config.xml
    \-resources (This ends up in docroot)
        \-resources
            \-js (Here they go your js files)
            \-comp (Here your composite components)
            \-css (Here your css)

Later on, you'll have to take care of avoiding the specific ids in your composites, as JSF modifies them while rendering. Your best is to pass the current component reference to your JS functions:

<h:inputText styleClass="myInputStyle" onclick="showInputText(this)" />

Just refer to included CSS styles and JS functions.

Last but not least, be careful when including the jar as a web resource, if the file paths remain in conflict with the ones in your web app, they won't be included.

See also:

Community
  • 1
  • 1
Aritz
  • 30,971
  • 16
  • 136
  • 217
  • 2
    @Biker I am working with Custom Components, rather than Composite Components, I think I should not create the "comp" directory, right? About the JS events: the render of the HTML is performed by a java class, not by an xhtml page (like in Composite Components), is it common (or well done) to attach a JS event to an element in the java renderer class, which is handled by a function within a JS file? – INElutTabile Jul 01 '14 at 14:00
  • @INElutTabile, this layout lets you decide how you want to implement your components. Composite components just add a xhtml view layer for their declaration, so if you want to go only with java code, you could, as everything achievable with composites can be done with custom components too. I infer you're playing with the framework, since using custom components for such a behaviour would be an overkill for me, moreover when JSF 2.x available. Here you have some related links: http://bit.ly/1lP5mKs http://bit.ly/VCPIIx – Aritz Jul 01 '14 at 17:11
  • 1
    @Biker Thanks for your help! I'd like you to add another important (IMHO) detail to your answer, if you can. I know that each JS resource that i need must be included within my page, in order to be used. I am using a Java renderer class, I guess I must include the js resource within such class, in order to use it. Right? Is it correct to perform a write within the renderer class, including my js resource, like 'responseWriter.write(" – INElutTabile Jul 02 '14 at 07:21
  • @Biker To answer your last question, I am using a Custom Compoent since I am dealing with a dynamic menu which can be n-levels deep, so I need recursive rendering of the items. I guesse that the right choice was to use a java renderer :) – INElutTabile Jul 02 '14 at 07:21
  • 1
    @INElutTabile you're welcome ;-) I have little experience with custom renderers, basically I have never had to implement one by myself. But yes, I think you're in the right way with the `responseWriter`. About your statement related with dynamic menu, there's no need to do it with custom renderer + no-facelets. That's an overkill. Go with composites, they can be also backed by a custom component and might have a facelet (view) associated. You could implement what you want just having a structure for your menu in the component and iterating over it with `ui:repeat` in your view. – Aritz Jul 02 '14 at 07:37
  • 1
    BTW, what you want to do has already [been implemented](http://www.primefaces.org/showcase/ui/menu/menu.xhtml). Whether you want to DIY or not is another story ;-) – Aritz Jul 02 '14 at 07:40
1

You can include into the facelets wich uses your component an external javascript file by adding the following code:

    <script src="#{request.contextPath}/jspath/yourjs.js"></script>

Within the component when you generate the XHTML output give an Id to your menu entries e.g.

    <h:outputText id="myid" value="#{bean.value}"/>

and in yourjs.js

    $(document).ready(function() {

    $("#myid").click(function(){
    // dostuff
    });
    });