1

I have a backend restservice call, returning a value, with which I have to execute a JS function (for simplicity, I took "alert" here, in the frontend. This has to be implemented in JSF, and I'm having a hard time.

And, this is the catch, for performance reasons, I want the backend rest-callto be executed on click.

Here is (amongst many other things), what I have tried:

<p:commandLink action="#{viewingSessionBean.prepareViewingSession(document)}" oncomplete="alert('#{viewingSessionBean.name(document)}')">
     <p:graphicImage value="documentViewerPopup.png"/>
</p:commandLink>

Here the bean (shortended to make the point clearer):

@ManagedBean
@ViewScoped
public class ViewingSessionBean implements Serializable {
     private String name;

     public String prepareViewingSession(Document document) {
          name = restClient.call()
          hashMap.put(document.getBlobId(), name);
          return null;  // don't navigate away...
     }

     public String name(Document document) {
         return hashMap.get(document.getBlobId()); // return null if nothing is cached for the document yet there
     }

}

I'd like to do something like this (pseudo code... don't have h:commandScript..., too old JSF, no way to upgrade)

 <h:commandScript action="alert('#{viewingSessionBean.prepareViewingSession(document)}') />

1 Answer 1

1

That's something a bit tricky to accomplish, but stil doable.

One thing you must have in mind first: The JavaScript code you write in a .xhtml is rendered in a 'static' way. But what means 'static'? It means that if you reference a bean variable inside of your JavaScript code, and then update this variable value inside your bean, your printed JavaScript code will not be able to see these changes you just made. In this case you must first update your JavaScript code (using ajax) to get the changes in your variable and only then execute it.

Let's start with your bean:

@ManagedBean
@ViewScoped
public class ViewingSessionBean implements Serializable {

     private String variable;

     public String getVariable() {
        return this.variable;
     }

     public void updateVariableValue(Document document) {
          variable = restClient.call();
     }

}

Now, the .xhtml code:

<h:form id="form">
    <p:commandLink id="firstLink"
                   actionListener="#{viewSessionBean.updateVariableValue(document)}" 
                   update=":form:secondLink"
                   oncomplete="$('#form\\:secondLink').click()"/>
    <p:commandLink id="secondLink" onclick="alert('#{viewSessionBean.variable}')" style="display: none;"/>
</h:form>

Note a few things:

First: It was used two commandLinks, and not only one, why? Because at the time of the oncomplete call of the first Link the bean variable is already up-to-date, but your html code is not. So in order to have the updated value of the bean variable we do the following things:

  • Call the actionListener to update the variable value on the bean;
  • Make an ajax update on the second Link to get the updated value from the bean;
  • Call the oncomplete method and call a click to the second Link (now updated with the correct values);

Second: To call the click on the second Link we must escape the two dots on the jQuery call.

Third: The second Link is set with the display: none style to make it invisible in the screen.

Now just some thoughts about it: JSF works pretty well alongside JavaScript, but sometimes we have to make some clumsy tricks like this one to accomplish an "easy" task. I'm not saying that JSF is bad, but I think we could have a more 'out-of-box' approach to these kind of things. Just my opinion though.

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

4 Comments

Awesome idea/pattern! I think, in the oncomplete event in "firstLink", you want to trigger $('#form\\:secondLink').click(), correct?
Another improvement for real live would be to use #{component.findComponent('secondLink').clientId} for the selection, which makes it easier to read in the code in a real-life situation, where you have maaaany divs etc stacked into each other. This results in <p:commandLink id="documentViewer" actionListener="#{viewingSessionBean.prepareViewingSession(document)}" update="viewTheViewer" oncomplete="jQuery(PrimeFaces.escapeClientId('#{component.findComponent('viewTheViewer').clientId}')).click()">
@Frischling yeah, the firstLink should call a secondLink click, updated my answer. You are also right about the jQuery select function, I omitted it to keep the answer as simple as possible. Thanks for the the heads up though ;)
I just put it there for completens' sake, for other newbies like me :)

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.