How to re-execute javascript function after form reRender?
Asked Answered
B

3

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.

Beano answered 26/10, 2012 at 5:18 Comment(0)
B
40

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>.

Botello answered 26/10, 2012 at 10:54 Comment(4)
Thanks BalusC! This seems to be simple and much straight way. It worked.Beano
Simply putting in h:outputScript helped me remove all oncomplete actions :)Beano
Very elegant solution @BotelloCattle
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 functionEncephalitis
B
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.

Backdate answered 15/12, 2013 at 15:6 Comment(1)
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. - thanksBackdate
D
-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.

Damien answered 26/10, 2012 at 7:20 Comment(3)
This won't work. This is only executed on DOM load/ready and this isn't re-executed on ajax requests.Botello
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 ?Damien
DOM ready event is not invoked on DOM manipulations as result of ajax responses.Botello

© 2022 - 2024 — McMap. All rights reserved.