How to Update Non-Jsf Components (Plain Html) With Jsf Ajax

Is it possible to update non-JSF components (plain HTML) with JSF ajax?

Is it possible to update parts of my page that are not JSF components?

No. The to-be-updated component has to be available by UIViewRoot#findComponent(), so that JSF can find them, invoke encodeAll() on it, capture the generated HTML output and pass back it in the ajax response so that JavaScript can update the HTML DOM tree with it. Plain HTML elements are not represented as real UIComponent instances in the JSF component tree, so JSF already cannot locate them in first place.



For example, can I update a plain HTML <div> or do I need to wrap that in a JSF component?

You need to wrap it in a JSF component like <h:panelGroup>. You can however just use <h:panelGroup layout="block"> to represent a real <div> in JSF. This way you don't need to wrap the <div> in another JSF component.

<h:panelGroup layout="block" id="foo">
...
</h:panelGroup>

Since JSF 2.2 you can use new passthrough elements feature with jsf:id attribute to declare HTML(5) elements as JSF components.

<... xmlns:jsf="http://xmlns.jcp.org/jsf">

<div jsf:id="foo">
...
</div>
<main jsf:id="bar">
...
</main>
<section jsf:id="baz">
...
</section>

They will render their output as-is, but under the covers be a concrete UIPanel instance.

There's however one corner case in case of composite components. You can use the following approach to have a HTML element which is updateable by ajax.

<cc:implementation>
<span id="#{cc.clientId}">
...
</span>
</cc:implementation>

The explanation that this approach works is because even though the composite component does not render itself to the HTML output, it is by itself available by UIViewRoot#findComponent().

See also:

  • How to find out client ID of component for ajax update/render? Cannot find component with expression "foo" referenced from "bar"
  • Why do I need to nest a component with rendered="#{some}" in another component when I want to ajax-update it?
  • Rerendering composite component by ajax

Ajax update of non-JSF component with PrimeFaces selectors

No, that's not possible. The update target must not only in client side be obtainable in HTML DOM tree by document.getElementById(), but also in server side by UIViewRoot#findComponent(), so that JSF can regenerate the desired HTML output which ultimately get applied during the ajax update.

If you supply JSF the ID of a plain HTML element, then it won't find anything in the component tree to regenerate the desired new HTML output for. Just replace the plain HTML element by a JSF component.

The PrimeFaces selectors get ultimately converted to HTML element IDs. PrimeFaces will loop over the elements found by the jQuery selector and extract their id attributes before passing to JSF. This is thus essentially the same problem as already answered here: Is it possible to update non-JSF components (plain HTML) with JSF ajax?.

Update component outside of h:form - ComponentNotFoundException

JSF can't see the id of your div if it is not a JSF component so you need to convert your div to a h:panelGroup

 <h:panelGroup id="entryDiv" layout="block">
<div>
<h:form id="myForm">
<c:forEach items="#{foodPlanManagementBean.loadRestaurantsHistory()}" var="restaurantHistoryEntry">
<p:commandButton value="MyName" update=":entryDiv"/>
</div>
</c:forEach>
</h:form>
</div>
</h:panelGroup>

if you don't put layout="block" it will render a span instead of a div.

Ajax-update another component inside same composite component

<h:inputText ...>
<f:ajax ...render="#{cc.clientId}:table#{cc.clientId}" />
</h:inputText>
<h:dataTable id="table#{cc.clientId}" ...>

This is unnecessarily clumsy. Both components are in the same naming container (the composite itself!), so the prefix is implicitly already done by the composite itself. The suffix is valid, but just unnecessary. The composite component's own ID already enforces the uniqueness in the context of its parent naming container component. Opening the page in browser, rightclick-view source and observing the IDs in generated HTML output should already have given insights about that.

Just keep it simple:

<h:inputText ...>
<f:ajax ...render="table" />
</h:inputText>
<h:dataTable id="table" ...>

See also:

  • How to find out client ID of component for ajax update/render? Cannot find component with expression "foo" referenced from "bar"
  • Is it possible to update non-JSF components (plain HTML) with JSF ajax?

How Can I Use Ajax To Update A GraphicImage Without Blinking?

You could bind an onevent attribute to your ajax tag:

<f:ajax render="productImage" listener="#{orderController.productSelectionChanged}" 
onevent="ajaxEventListener"/>

Then, you get notified whenever some phase of the ajax process happens. You might be interested in implementing something like this with jQuery:

function ajaxEventListener(data) {
var status = data.status; // Can be "begin", "complete" or "success".
var source = data.source; // The parent HTML DOM element.
//Give your form an id in order to access the image in JS
var $image = $(document.getElementById("yourFormId:productImage")); //Grab your image

switch (status) {
case "begin": // Before the ajax request is sent.
// Fade out your image
$image.fadeOut( "slow" );
break;

case "success": // After update of HTML DOM based on ajax response.
// You've got the url properly updated, start fading in the image again
$image.fadeIn( "slow" );
break;
}
}

In order to improve loading times, you should read some papers about how to cache resources in the web browser. That's not JSF specific, though, it's something you could do with a web filter.

See also:

  • Execute JavaScript before and after the f:ajax listener is invoked
  • How to select JSF components using jQuery?
  • http://api.jquery.com/fadeout/
  • http://api.jquery.com/fadeIn/

Update preRenderView component with ajax

Use the preRenderComponent event instead and put those f:events inside the divs.

I'm not sure if it will play nicely with this kind of JSF binding though. You may have to replace those divs with h:panelGroup layout="block" (which renders simple divs as well).



Related Topics



Leave a reply



Submit