dev@jsf-extensions.java.net

Re: [JSF-EXT] Jacob: Seeking Review: 7-Immediate

From: <jacob_at_hookom.net>
Date: Tue, 15 Aug 2006 18:27:38 -0400

I agree with Dan.

>Is calling setImmediate(true) on a component the only way to achieve
>this behavior? I like the idea of adding an immediate flag as a property
>of DynaFaces.fireAjaxTransaction, but I'm concerned that the value is
>persisted via component state.
>
>I would like immediate behavior during the AJAX request, but I do not
>want this to persist for subsequent page submits. For example, I would
>like to use the immediate behavior to auto-validate a text field during
>an AJAX request because I do not want its value to be updated. However,
>if the user clicks a button to submit the page, I expect the text field
>value to be updated. If the immediate property is persisted, how will
>the text field value be updated in the model?
>
>Dan
>
>Ed Burns wrote:
>> https://jsf-extensions.dev.java.net/issues/show_bug.cgi?id=7
>>
>> This is checked in on branch IMMEDIATE_20060815
>>
>> I'd like to get everyone's feedback on this issue.
>>
>> Issue: DynaFaces-7-immediate
>>
>> This change-bundle adds the 'immediate' option to the set of supported
>> options for the associative array passed as the last argument to
>> DynaFaces.fireAjaxTransaction() and
>> DynaFaces.installDeferredAjaxTransaction(). For example:
>>
>> + DynaFaces.installDeferredAjaxTransaction($('immediate'), 'click', {
>> + execute: "immediate",
>> + immediate: true
>> + });
>>
>> This will end up locating the component with clientId 'immediate' and
>> calling setImmediate(true) on it *if* the component is an instance of
>> EditableValueHolder or ActionSource. This call is made before the
>> partial tree list is traversed for processDecodes, and naturally, the
>> 'immediate' property is persisted as part of the component instance's
>> view state.
>>
>> SECTION: Changes
>>
>> M run-time/samples/simple-partial-update/src/main/webapp/home.jsp
>>
>> - modify to showcase immediate vs non-immediate usage.
>>
>> M
>run-time/common/src/main/java/com/sun/faces/extensions/common/util/Util.java
>>
>> - copy over prefixViewTraversal from Sun JSF Impl.
>>
>> M
>run-time/avatar/src/main/java/com/sun/faces/extensions/avatar/lifecycle/AsyncRe
>sponse.java
>>
>> - add isImmediateAjaxRequest() method.
>>
>> + * <p>Return <code>true</code> if and only if the request headers
>include
>> + * an entry for {_at_link #PARTIAL_HEADER} and the value for that header
>is
>> + * <code>immediate</code>. Otherwise return <code>false</code>.
>>
>> M
>run-time/avatar/src/main/java/com/sun/faces/extensions/avatar/components/Partia
>lTraversalViewRoot.java
>>
>> - in processDecodes(), handle the case where this is an immediate request
>> but no partial trees have been identified. In this case, the entire
>> tree is traversed and all ActionSource or EditableValueHolder
>> instances are set to immediate == true.
>>
>>
>> - in the partial traversal ContextCallback, if this is
>> APPLY_REQUEST_VALUES, and the current component instance is an
>> ActionSource or EditableValueHolder, and this is an immediate request,
>> set immediate == true.
>>
>> M run-time/avatar/src/main/resources/com_sun_faces_ajax.js
>>
>> - If the user specified an immediate option, set the value of the
>> partial header to be 'immediate'.
>>
>> M pom.xml
>>
>> - add common and simple-partial-update to samples profile.
>>
>> SECTION: Diffs
>>
>> Index: run-time/samples/simple-partial-update/src/main/webapp/home.jsp
>> ===================================================================
>> --- run-time/samples/simple-partial-update/src/main/webapp/home.jsp
>(revision 187)
>> +++ run-time/samples/simple-partial-update/src/main/webapp/home.jsp (working
>copy)
>> @@ -42,11 +42,26 @@
>>
>> </tr>
>>
>> +<tr>
>> +
>> +<td>Same as above but with immediate set to true.</td>
>> +
>> +<td><h:commandButton id="immediate"
>actionListener="#{testBean.changeText}"
>> + value="submit"/>
>> +</td>
>> +
>> +</tr>
>> +
>> +
>> </table>
>>
>> </h:form>
>> <script type='text/javascript'>
>> DynaFaces.installDeferredAjaxTransaction($('button'), 'click');
>> + DynaFaces.installDeferredAjaxTransaction($('immediate'), 'click', {
>> + execute: "immediate",
>> + immediate: true
>> + });
>> </script>
>>
>>
>> Index:
>run-time/common/src/main/java/com/sun/faces/extensions/common/util/Util.java
>> ===================================================================
>> ---
>run-time/common/src/main/java/com/sun/faces/extensions/common/util/Util.java
>(revision 187)
>> +++
>run-time/common/src/main/java/com/sun/faces/extensions/common/util/Util.java
>(working copy)
>> @@ -25,7 +25,9 @@
>>
>> package com.sun.faces.extensions.common.util;
>>
>> +import java.util.Iterator;
>> import java.util.List;
>> +import javax.faces.FacesException;
>> import javax.faces.FactoryFinder;
>> import javax.faces.application.Application;
>> import javax.faces.component.UIComponent;
>> @@ -137,4 +139,25 @@
>> RenderKit curRenderKit = fact.getRenderKit(context, renderKitId);
>> return curRenderKit;
>> }
>> +
>> + public static boolean prefixViewTraversal(FacesContext context,
>> + UIComponent root,
>> + TreeTraversalCallback action) throws FacesException {
>> + boolean keepGoing = false;
>> + if (keepGoing = action.takeActionOnNode(context, root)) {
>> + Iterator<UIComponent> kids = root.getFacetsAndChildren();
>> + while (kids.hasNext() && keepGoing) {
>> + keepGoing = prefixViewTraversal(context,
>> + kids.next(),
>> + action);
>> + }
>> + }
>> + return keepGoing;
>> + }
>> +
>> + public static interface TreeTraversalCallback {
>> + public boolean takeActionOnNode(FacesContext context,
>> + UIComponent curNode) throws FacesException;
>> + }
>> +
>> }
>> Index:
>run-time/avatar/src/main/java/com/sun/faces/extensions/avatar/lifecycle/AsyncRe
>sponse.java
>> ===================================================================
>> ---
>run-time/avatar/src/main/java/com/sun/faces/extensions/avatar/lifecycle/AsyncRe
>sponse.java (revision 187)
>> +++
>run-time/avatar/src/main/java/com/sun/faces/extensions/avatar/lifecycle/AsyncRe
>sponse.java (working copy)
>> @@ -314,7 +314,32 @@
>> }
>> return result;
>> }
>> +
>> + /**
>> + * <p>Return <code>true</code> if and only if the request headers
>include
>> + * an entry for {_at_link #PARTIAL_HEADER} and the value for that header
>is
>> + * <code>immediate</code>. Otherwise return <code>false</code>.
>> + */
>>
>> + public static boolean isImmediateAjaxRequest() {
>> + ExternalContext ext =
>FacesContext.getCurrentInstance().getExternalContext();
>> + Map<String, Object> requestMap = ext.getRequestMap();
>> + final String immediateFlag = FACES_PREFIX + "IsImmediate";
>> + if (requestMap.containsKey(immediateFlag)) {
>> + return true;
>> + }
>> +
>> + Map<String, String> p = ext.getRequestHeaderMap();
>> + String partialValue = p.get(PARTIAL_HEADER);
>> + boolean result = false;
>> + if (null != partialValue) {
>> + result = partialValue.equalsIgnoreCase("immediate");
>> + }
>> + if (result) {
>> + requestMap.put(immediateFlag, Boolean.TRUE);
>> + }
>> + return result;
>> + }
>> private Object origResponse = null;
>>
>> /**
>> Index:
>run-time/avatar/src/main/java/com/sun/faces/extensions/avatar/components/Partia
>lTraversalViewRoot.java
>> ===================================================================
>> ---
>run-time/avatar/src/main/java/com/sun/faces/extensions/avatar/components/Partia
>lTraversalViewRoot.java (revision 187)
>> +++
>run-time/avatar/src/main/java/com/sun/faces/extensions/avatar/components/Partia
>lTraversalViewRoot.java (working copy)
>> @@ -31,13 +31,16 @@
>>
>> import com.sun.faces.extensions.avatar.event.EventParser;
>> import com.sun.faces.extensions.avatar.lifecycle.AsyncResponse;
>> +import com.sun.faces.extensions.common.util.Util;
>> import java.io.IOException;
>> import java.io.Serializable;
>> import java.util.Iterator;
>> import java.util.List;
>> import javax.faces.FacesException;
>> import javax.faces.application.FacesMessage;
>> +import javax.faces.component.ActionSource;
>> import javax.faces.component.ContextCallback;
>> +import javax.faces.component.EditableValueHolder;
>> import javax.faces.component.UIComponent;
>> import javax.faces.component.UIViewRoot;
>> import javax.faces.component.UIViewRootCopy;
>> @@ -137,11 +140,35 @@
>> super.processDecodes(context);
>> return;
>> }
>> + AsyncResponse async = AsyncResponse.getInstance();
>> +
>> + // If this is an immediate "render all" request and there are
>> + // no explicit execute subtrees and the user didn't request
>> + // execute: none...
>> + if (async.isImmediateAjaxRequest() && async.isRenderAll() &&
>> + async.getExecuteSubtrees().isEmpty() &&
>> + !async.isExecuteNone()) {
>> + // Traverse the entire view and mark every ActionSource or
>> + // EditableValueHolder as immediate.
>> + Util.TreeTraversalCallback markImmediate = new
>Util.TreeTraversalCallback() {
>> + public boolean takeActionOnNode(FacesContext context,
>UIComponent comp) throws FacesException {
>> + if (comp instanceof ActionSource) {
>> + ((ActionSource)comp).setImmediate(true);
>> + } else if (comp instanceof EditableValueHolder) {
>> + ((EditableValueHolder)comp).setImmediate(true);
>> + }
>> +
>> + return true;
>> + }
>> +
>> + };
>> + Util.prefixViewTraversal(context, this, markImmediate);
>> + }
>> +
>> invokedCallback = invokeContextCallbackOnSubtrees(context,
>> new
>PhaseAwareContextCallback(PhaseId.APPLY_REQUEST_VALUES));
>>
>> // Queue any events for this request in a context aware manner
>> - AsyncResponse async = AsyncResponse.getInstance();
>> ResponseWriter writer = null;
>> try {
>> writer = async.getResponseWriter();
>> @@ -384,15 +411,22 @@
>> ConverterException converterException = null;
>>
>> if (curPhase == PhaseId.APPLY_REQUEST_VALUES) {
>> + // If the user requested an immediate request
>> + // Make sure to set the immediate flag.
>> + if (AsyncResponse.isImmediateAjaxRequest()) {
>> + if (comp instanceof ActionSource) {
>> + ((ActionSource)comp).setImmediate(true);
>> + } else if (comp instanceof EditableValueHolder) {
>> +
>((EditableValueHolder)comp).setImmediate(true);
>> + }
>> + }
>> +
>> comp.processDecodes(facesContext);
>> - }
>> - else if (curPhase == PhaseId.PROCESS_VALIDATIONS) {
>> + } else if (curPhase == PhaseId.PROCESS_VALIDATIONS) {
>> comp.processValidators(facesContext);
>> - }
>> - else if (curPhase == PhaseId.UPDATE_MODEL_VALUES) {
>> + } else if (curPhase == PhaseId.UPDATE_MODEL_VALUES) {
>> comp.processUpdates(facesContext);
>> - }
>> - else if (curPhase == PhaseId.RENDER_RESPONSE) {
>> + } else if (curPhase == PhaseId.RENDER_RESPONSE) {
>> ResponseWriter writer =
>AsyncResponse.getInstance().getResponseWriter();
>>
>> writer.startElement("render", comp);
>> Index: run-time/avatar/src/main/resources/com_sun_faces_ajax.js
>> ===================================================================
>> --- run-time/avatar/src/main/resources/com_sun_faces_ajax.js (revision 187)
>> +++ run-time/avatar/src/main/resources/com_sun_faces_ajax.js (working copy)
>> @@ -481,7 +481,12 @@
>>
>> // guarantee our header
>> this.options.requestHeaders.push(gPartial);
>> - this.options.requestHeaders.push('true');
>> + if (this.options.immediate) {
>> + this.options.requestHeaders.push('immediate');
>> + }
>> + else {
>> + this.options.requestHeaders.push('true');
>> + }
>>
>> // add methodName
>> if (this.options.methodName) {
>> Index: pom.xml
>> ===================================================================
>> --- pom.xml (revision 187)
>> +++ pom.xml (working copy)
>> @@ -145,11 +145,13 @@
>> <profile>
>> <id>samples</id>
>> <modules>
>> + <module>run-time/common</module>
>> <module>run-time/avatar</module>
>> <module>run-time/samples/j1</module>
>> <module>run-time/samples/cardemo</module>
>> <module>run-time/samples/jmaki</module>
>> <module>run-time/samples/simple-events</module>
>> + <module>run-time/samples/simple-partial-update</module>
>> </modules>
>> </profile>
>> <profile>
>>
>>
>>
>
>---------------------------------------------------------------------
>To unsubscribe, e-mail: dev-unsubscribe_at_jsf-extensions.dev.java.net
>For additional commands, e-mail: dev-help_at_jsf-extensions.dev.java.net
>