17

I need to re-execute javascript just after form gets re-rendered. Simply, putting in javascript after XHTML content won't help since its a partial request. Also, I cannot use "onComplete" as the commandButton from which I am re-rendering form is in JSF component used at several places. I need to get the fix in locally.

Is there any way? I was wondering whether f:ajax would help in this case.

Please let me know, if anyone has clue about it.

3 Answers 3

41

Simplest way is to just put the JS function call in the to-be-updated component itself.

<h:form>
    ...
    <h:commandButton value="submit"><f:ajax render="@form" /></h:commandButton>
    <h:outputScript>someFunction();</h:outputScript>
</h:form>

This way it's executed as the page loads and also if the form get updated by ajax.

As to the <f:ajax> itself, you could also use its onevent attribute.

<f:ajax ... onevent="handleAjax" />

with

function handleAjax(data) {
    var status = data.status;

    switch(status) {
        case "begin":
            // This is invoked right before ajax request is sent.
            break;

        case "complete":
            // This is invoked right after ajax response is returned.
            break;

        case "success":
            // This is invoked right after successful processing of ajax response and update of HTML DOM.
            someFunction();
            break;
    }
}

You could add a global hook by jsf.ajax.addOnEvent() so that you don't need to specify it in every single onevent attribute of <f:ajax> if the functional requirement applies to every ajax request.

jsf.ajax.addOnEvent(handleAjax);

An alternative is to use the OmniFaces JSF utility library which offers the <h:onloadScript> for exactly this purpose. You can place it in the head so you want.

<h:onloadScript>someFunction();</h:onloadScript>

This is automatically re-excuted on every single ajax request on the view so that you don't need to copy it over multiple individual places in the view which can be ajax-updated, or to repeat its parent ID in every <f:ajax render>.

Sign up to request clarification or add additional context in comments.

4 Comments

Thanks BalusC! This seems to be simple and much straight way. It worked.
Simply putting in h:outputScript helped me remove all oncomplete actions :)
Very elegant solution @BalusC
When I put JS function in h:outputScript it is executed but it throws error from other used by it scripts e.g. $(...).datetimepicker is not a function
0

BalusC first answer is the most appropriate if you want to do complex operations with JQuery/JS and are not particularly concerned about this

For more complex JS, if you decide to use a global event handler and for example you use JS to bind functions to elements, these functions are going to be re-bound (hence executed twice), so you need some way to identify what needs to be re-executed.

What I finally did, was to get the id's from the event callback and execute only the relevant JS/JQuery:

jsf.ajax.addOnEvent(ajaxCompleteProcess);


function ajaxCompleteProcess(data) {
    if (data.status && data.status === 'success') {
        var children1 = data.responseXML.children;
        for (i = 0; i < children1.length; i += 1) {
            var children2 = children1[i].children;
            for (j = 0; j < children2.length; j += 1) {
                var children3 = children2[j].children;
                for (y = 0; y < children3.length; y += 1) {
                    if (children3[y].id.indexOf('javax.faces.ViewState') != -1)
                        continue;
                    elementProcess(('#' + children3[y].id.replace(/\:/g, '\\:')));
                }
            }
        }
    }
}

Note: these ugly for loops are probably not required (you could use clildren[0]), but I haven't found the time yet to check the spec.

1 Comment

Would be nice to know the reason for the down vote. This does work and the only bit of code you need is this for your whole application. So, it's either a bad post or there is bad for some reason. - thanks
-1

You could add jQuery to your application and do something like:

$(#yourComponentId).load(function(){
   //execute javascript.
});

You can take a look here http://api.jquery.com/load/

LE: that being on

$(document).ready(function(){
}

ofc.

3 Comments

This won't work. This is only executed on DOM load/ready and this isn't re-executed on ajax requests.
At document-ready event, we hook the function which will execute each time component with id=yourComponentId triggers the 'load' event. Maybe it was better to exec the function at 'ready' event of the component, but anyway, I think this will work. What do you think BalusC ?
DOM ready event is not invoked on DOM manipulations as result of ajax responses.

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.