14

JSF 2.0, Mojarra 2.0.1, PrimeFaces 3.4.1

There are similar questions but I need sth. else; javascript function has to wait for the backing bean method, which is filling the variable that wanted to be pulled from js function. What I want to say is:

<p:commandLink action="#{statusBean.getStatuses}" oncomplete="afterLoad()"/>

Assuming js function just getting the value and printing it to the screen.

function afterLoad() {    
    alert("#{statusBean.size}");
}

And here is the birthday kid:

@ManagedBean
@ViewScoped
public class StatusBean {
    public int size=0;
    List<Status> panelList = new ArrayList<Status>();
    public void getStatuses() {
        this.panelList = fillList();
        this.size = panelList.size(); //Assuming 3
    }
    //getter and setters
}

So function alerts the size as 0 which is the initial value of it, while we're expecting to see 3.

How it's working: If I add the @PostConstruct annotation to bean's head surely it gets the correct size, because bean is already constructed before the page load. But this means redundant processes, value just needed after the commandlink action. So how to postpone the js function? Any ideas?

Luiggi Mendoza
  • 85,076
  • 16
  • 154
  • 332
Ömer Faruk Almalı
  • 3,792
  • 6
  • 37
  • 63
  • 1
    Mojarra 2.0.1 is ancient. It's over 3 years old already. Consider upgrading. There are many, many bugfixes and improvements in the current 2.1.19 version. – BalusC Feb 19 '13 at 20:12
  • @BalusC Ok I am going to review the version differences, also both answers are correct and working thank you and partlov but I couldn't decide to which one should be selected as the answer. Should I choose due to first come first served basis? But server says you answered 1 min ago but when I last looked it was saying partlov answered first. Is it same-time? – Ömer Faruk Almalı Feb 19 '13 at 20:27
  • Just choose the one which is most helpful to you. The answers posted so far do not provide exactly the same information. As to the exact answer timestap, just check the tooltip of the "answered" timestamp. But you should not consider this in choosing the answer. This only simulates the FGITW. – BalusC Feb 19 '13 at 20:28

2 Answers2

26

JSF/EL and HTML/JS doesn't run in sync. Instead, JSF/EL run in webserver and produces HTML/JS which in turn runs in webbrowser. Open page in browser, rightclick and View Source. You see, there's no single line of JSF/EL. It's one and all HTML/JS. In place of your JS function, you'll see:

function afterLoad() {    
    alert("0");
}

Exactly this JS function get invoked on complete of your command button action. So the result is fully expected.

Basically, you want to let JSF re-render that piece of JS.

<p:commandLink action="#{statusBean.getStatuses}" update="afterLoad" oncomplete="afterLoad()"/>
<h:panelGroup id="afterLoad">
    <h:outputScript>
        function afterLoad() {    
            alert("#{statusBean.size}");
        }
    </h:outputScript>
</h:panelGroup>

Depending on the concrete functional requirement, which you didn't tell anything about, there may be more elegant ways. For example, RequestContext#execute(), <o:onloadScript>, etc.

BalusC
  • 1,082,665
  • 372
  • 3,610
  • 3,555
11

EL in your JavaScript is calculated when page is rendered and you can update its container (if it is in some JSF component), but I would suggest another approach.

As you are making AJAX request, you can add callback parameter in getStatuses() method. You can use Primefaces's RequestContext utility method addCallBackParam() for this:

public void getStatuses() {
    this.panelList = fillList();
    this.size = panelList.size();
    RequestContext.getCurrentInstance().addCallBackParam("size", this.size);
}

and you can use this parameter in xhtml:

<p:commandLink action="#{statusBean.getStatuses}" oncomplete="afterLoad(xhr, status, args)"/>

<script type="text/javascript">
  function afterLoad(xhr, status, args) {    
    alert(args.size);
  }
</script>
partlov
  • 13,789
  • 6
  • 63
  • 82
  • Hello again, I've an issue about `addCallBackParam`. It works perfect when using the `afterLoad(xhr,status,args)` at first invocation. But If I want to call it for second time using same `getStatuses()`, in the afterLoad method `size` becomes `undefined`. It seems it can not adds call back param correctly on second invocation. What I mean with second invocation is: for example user adds a status and afterLoad works after that successfully, but If user deletes a status, I've defined a `remotecommand` it calls `statusBean.getStatuses` and it has `oncomplete="afterLoad(xhr,status,args)`. – Ömer Faruk Almalı Apr 14 '13 at 08:41