1

How can I add server side what is sent in all ajax responses so that I can add my own parameters?

I have extended richfaces JavaScript A4J.AJAX.finishRequest to trigger a custom event and I would like to pass parameters to it from the server:

var originalFinishRequest = A4J.AJAX.finishRequest;

A4J.AJAX.finishRequest = function(request) {
    var parameters = request.options.parameters;
    if (!request._oncomplete_aborted) {

       jQuery(document).trigger('onAutofocus',parameters);
    }
    originalFinishRequest(request);
};

Another way of looking at it would be, what responds server side to calls to A4J.AJAX.Submit and how do I wrap my own code around that?


My solution

This is what I ended up putting in my master template, based on BalusC's answer:

<a4j:outputPanel ajaxRendered="true">
  <c:if test="#{not empty flowScope.autofocusSelectors}">
    <script>
      document.autofocusSelectors = #{flowScope.autofocusSelectors};
      console.log("BASE TEMPLATE: autofocus: (#{flowScope.autofocusSelectors})");
    </script>
  </c:if>
  <script>
    console.log("BASE TEMPLATE AJAX RENDER")
    //NB: autofocusSelectors not always set, and not only reason to autofocus
    jQuery(document).trigger('onAutofocus');
  </script>
</a4j:outputPanel>
Sam Hasler
  • 12,344
  • 10
  • 72
  • 106

1 Answers1

0

Whilst this is easy in JSF2 which has standardized the one and other, this is not exactly trivial in RichFaces 3.x Ajax4jsf. Ajax responses are handled by org.ajax4jsf.Filter which in turn extends from among others BaseXmlFilter. All the ajax response writing code is in there. It's not abstracted in such way that it allows easy adding of custom tags/scripts. You'd basically need to copy'n'paste'n'modify it. It just isn't worth the effort.

An easier way is to just auto-ajax-render some piece of <script> containing the desired variables in JS flavor so that the bean properties could be assigned as a global JS variable.

<a4j:outputPanel ajaxRendered="true">
    <script type="text/javascript">
        var parameters = <h:outputText value="#{bean.paramsAsJson}" />;
    </script>
</a4j:outputPanel>

(the ajaxRendered="true" ensures that this is auto-rerendered on every ajax request, so that you don't need to explicitly add its ID to the reRender attribute of some A4J component)

Where getParamsAsJson() just returns a Java string in valid JSON format something like as { foo: "foo", bar: "bar" }. This way you can just use

A4J.AJAX.finishRequest = function(request) {
    if (!request._oncomplete_aborted) {
       jQuery(document).trigger('onAutofocus', parameters);
    }
    originalFinishRequest(request);
};

(note that request.options.parameters basically contains the request parameters which are sent by the client upon firing the ajax request, not the variables which are set by the server side on returning the ajax response, so it was in first place already wrong to look at it)

Further, I'm not exactly sure why you're overriding A4J.AJAX.finishRequest like that instead of using <a4j:status onstop="...">, but assuming that you just weren't aware of it, here's how you could make use of it instead:

<a4j:status onstop="jQuery(document).trigger('onAutofocus', parameters)" />
BalusC
  • 1,082,665
  • 372
  • 3,610
  • 3,555
  • I was trying to extend `request.options.parameters` with extra server side parameters as that seemed tidier than picking up global JS variables as I didn't want to insert scripts wherever I use this. I wasn't aware of the ajaxRendered technique but if I'm able to use that in my base template it looks like a good solution. – Sam Hasler Jan 03 '13 at 14:27
  • The `request.options.parameters` represents the HTTP request parameter map which is already populated before sending the ajax request. This is definitely not mutable from the server side on. – BalusC Jan 03 '13 at 14:29
  • I was aware of `a4j:status onstop` but it's already used in the code for other things, and I believe it can only be defined once. I also want to avoid having to add tags on every page. – Sam Hasler Jan 03 '13 at 14:29
  • Consider using Facelets instead of JSP, then you can have a single master template. But ala, it's likely not worth the effort on such a legacy app. – BalusC Jan 03 '13 at 14:30
  • maybe it's cos I'm a front end dev trying to get the server side stuff to make my life easier, so I don't know richfaces as well as I should (yet), but I'm not sure how I gave the impression I wasn't using facelets. – Sam Hasler Jan 03 '13 at 14:35
  • If you were using Facelets, you would not have said *"I also want to avoid having to add tags on every page"* which is one of the major payoffs of using JSP and one of the top reasons using Facelets. – BalusC Jan 03 '13 at 14:37
  • I guess I meant facelet instead of page, if that makes any more sense. I just wanted to have one place in the facelets handling setting the parameters. I've now added an outputPanel in my base template that inserts a script if any flowscope variables have been set that I want to pass to JavaScript event handlers. I think I can probably trigger the event handlers from there as well so I won't need to override A4J.AJAX.finishRequest any more either. Thanks! – Sam Hasler Jan 04 '13 at 16:52
  • You're welcome. Coming back to the templating, if you're indeed using Facelets, probably you missed one of its biggest powers. Check the 2nd example in this answer: http://stackoverflow.com/questions/4792862/how-to-include-another-xhtml-in-xhtml-using-jsf-2-0-facelets/4793959#4793959 You could just have used `` in the "master template" page. – BalusC Jan 04 '13 at 16:55
  • That's the way we're doing templating. I'd use `` if I didn't have to have a ``. I've added my solution to the question. – Sam Hasler Jan 07 '13 at 11:59