Home | Download | PDF | API | FAQ | Search | Feedback | History

> ## Delegating Rendering to a Renderer

> Both `MapComponent` and `AreaComponent` delegate all of their rendering to a separate renderer. The section Performing Encoding explains how `MapRenderer` performs the encoding for `MapComponent`. This section explains in detail the process of delegating rendering to a renderer using `AreaRenderer`, which performs the rendering for `AreaComponent`.

> To delegate rendering, you perform these tasks:

> - Create the `Renderer` class
> - Register the renderer with a render kit (explained in Registering a Custom Renderer with a Render Kit, page 468)
> - Identify the renderer type in the component's tag handler

> ### Creating the Renderer Class

> When delegating rendering to a renderer, you can delegate all encoding and decoding to the renderer, or you can choose to do part of it in the component class. The `AreaComponent` class delegates encoding to the `AreaRenderer` class.

> To perform the rendering for `AreaComponent`, AreaRenderer must implement an `encodeEnd` method. The `encodeEnd` method of `AreaRenderer` retrieves the shape, coordinates, and alternative text values stored in the `ImageArea` bean that is bound to `AreaComponent`. Suppose that the `area` tag currently being rendered has a `value` attribute value of `"fraA"`. The following line from `encodeEnd` gets the value of the attribute `"fraA"` from the FacesContext instance.

>     ImageArea ia = (ImageArea)area.getValue();

> The attribute value is the `ImageArea` bean instance, which contains the shape, coordinates, and alt values associated with the `fraA` `AreaComponent` instance. Configuring Model Data describes how the application stores these values.

> After retrieving the `ImageArea` object, it renders the values for `shape`, `coords`, and `alt` by simply calling the associated accessor methods and passing the returned values to the `ResponseWriter` instance, as shown by these lines of code, which write out the shape and coordinates:

>     writer.startElement("area", area);
>     writer.writeAttribute("alt", iarea.getAlt(), "alt");
>     writer.writeAttribute("coords", iarea.getCoords(), "coords");
>     writer.writeAttribute("shape", iarea.getShape(), "shape");

> The `encodeEnd` method also renders the JavaScript for the `onmouseout`, `onmouseover`, and `onclick` attributes. The page author need only provide the path to the images that are to be loaded during an `onmouseover` or `onmouseout` action:

>     <bookstore:area id="France" value="#{fraA}"
>       onmouseover="/template/world_france.jpg"
>       onmouseout="/template/world.jpg" targetImage="mapImage" />

> The `AreaRenderer` class takes care of generating the JavaScript for these actions, as shown in the following code from `encodeEnd`. The JavaScript that `AreaRenderer` generates for the `onclick` action sets the value of the hidden field to the value of the current area's component ID and submits the page.

>     sb = new StringBuffer("document.forms[0]['").
>       append(targetImageId).append("'].src='");
>     sb.append(getURI(context,
>       (String) area.getAttributes().get("onmouseout")));
>     sb.append("'");
>     writer.writeAttribute("onmouseout", sb.toString(),
>       "onmouseout");
>     sb = new StringBuffer("document.forms[0]['").
>       append(targetImageId).append("'].src='");
>     sb.append(getURI(context,
>       (String) area.getAttributes().get("onmouseover")));
>     sb.append("'");
>     writer.writeAttribute("onmouseover", sb.toString(),
>       "onmouseover");
>     sb = new StringBuffer("document.forms[0]['");
>     sb.append(getName(context, area));
>     sb.append("'].value='");
>     sb.append(iarea.getAlt());
>     sb.append("'; document.forms[0].submit()");
>     writer.writeAttribute("onclick", sb.toString(), "value");
>     writer.endElement("area");

> By submitting the page, this code causes the JavaServer Faces life cycle to return back to the restore view phase. This phase saves any state information--including the value of the hidden field--so that a new request component tree is constructed. This value is retrieved by the `decode` method of the `MapComponent` class. This `decode` method is called by the JavaServer Faces implementation during the apply request values phase, which follows the restore view phase.

> In addition to the `encodeEnd` method, `AreaRenderer` contains an empty constructor. This is used to create an instance of `AreaRenderer` so that it can be added to the render kit.

> ### Identifying the Renderer Type

> During the render response phase, the JavaServer Faces implementation calls the `getRendererType` method of the component's tag handler to determine which renderer to invoke, if there is one.

> The `getRendererType` method of `AreaTag` must return the type associated with `AreaRenderer`. You identify this type when you register `AreaRenderer` with the render kit, as described in Registering a Custom Renderer with a Render Kit (page 468). Here is the `getRendererType` method from the `AreaTag` class:

>     public String getRendererType() { return ("DemoArea");}

> Creating the Component Tag Handler explains more about the `getRendererType` method.