1

I use omnifaces and their socket to implement a one-side web-socket based connection from the server to the client.

I follow their showcase

http://showcase.omnifaces.org/push/socket
http://omnifaces.org/docs/javadoc/3.4/org/omnifaces/cdi/push/Socket.html#ui

  <h:form>
      <o:socket channel="someChannel" scope="view">
          <f:ajax event="someEvent" listener="#{bean.pushed}" render=":foo" 
      </o:socket>
  </h:form>

It's nice that I can do UI updates once a message is received on the frontend. In my case, though, someEvent is more complex than a String. It's an object

{
    "event": "refresh",
    "render": "id1 id2"
}

and neither event not render attribute is known beforehand.

Is it possible to trigger ajax rendering based on event's message data?

(pseudocode here)

<f:ajax event="<this-event>.event" render="<this-event>.render" />
Kukeltje
  • 12,223
  • 4
  • 24
  • 47
Andrew Tobilko
  • 48,120
  • 14
  • 91
  • 142
  • Then do the `render` from the bean, there your have full control. – Kukeltje Nov 13 '19 at 10:15
  • If you had Primefaces, `PrimeFaces.current().ajax().update("id1", "id2")` while processing an AJAX event – Selaron Nov 13 '19 at 10:18
  • Posting "update component from bean jsf" or "render component from bean jsf" in a searcjengine would have helped. https://stackoverflow.com/questions/11365094/can-i-update-a-jsf-component-from-a-jsf-backing-bean-method – Kukeltje Nov 13 '19 at 11:01
  • @Selaron the comment you've just added under Kukeltje's answer (and removed) is exactly what I am trying to do. The problem is I receive an `AjaxBehaviorEvent event` and I can't extract the data needed from it – Andrew Tobilko Nov 13 '19 at 11:13
  • @AndrewTobilko I had hit [enter] to early while writing and deleted and finished it. – Selaron Nov 13 '19 at 11:15

2 Answers2

2

No there is no option to do things like this. The solution is to update from the server side in the bean. How to do this can be read in:

Kukeltje
  • 12,223
  • 4
  • 24
  • 47
  • The o:socket can be used to **trigger** an ajax call and then methods linked by you can be used to decide server side **which** components to update. So I aggree with your **no**. A work around might be to remove f:ajax from o:socket and pass the IDs to a p:remoteCommand. I don't see the use case tho ^^ – Selaron Nov 13 '19 at 11:14
  • @Selaron how specifically would you "pass the IDs to a p:remoteCommand"? Could you elaborate on it? – Andrew Tobilko Nov 13 '19 at 11:17
  • Thank you for your answer. Upvoted. If I go with this option, I will be populating `renderIds` ("*These client identifiers are used to identify components that will be processed during the render phase of the request processing lifecycle.*"). It means this render phase will start after my method is finished. What I want is updating while the method is running. This method is basically a huge loop and after each iteration I want some components to be updated. – Andrew Tobilko Nov 13 '19 at 11:28
  • @AndrewTobilko you should really attmempt Kukeltjes solution, your managed beans should know which components to update, not? If there's no other way, take a look here: https://stackoverflow.com/a/18510102/865107 – Selaron Nov 13 '19 at 11:29
2

You can use multiple <f:ajax> tags with each a different event and their own render targets.

<h:form>
    <o:socket channel="someChannel" scope="view">
        <f:ajax event="refresh1and2" render="id1 id2" />
        <f:ajax event="refresh3and4" render="id3 id4" />
        <f:ajax event="refresh5and6" render="id5 id6" />
    </o:socket>
</h:form>

And then do any of following:

someChannel.send("refresh1and2");

someChannel.send("refresh3and4");

someChannel.send("refresh5and6");

Alternatively, if your render targets are actually dynamic, then attach a listener and let it perform Ajax#update().

<h:form>
    <o:socket channel="someChannel" scope="view">
        <f:ajax event="refresh" listener="#{bean.refreshAfterPush}" />
    </o:socket>
</h:form>

with

someChannel.send("refresh");

and

public void refreshAfterPush() {
    Ajax.update("id1", "id2");
}
BalusC
  • 1,082,665
  • 372
  • 3,610
  • 3,555
  • Thank you for your answer. Multiple `ajax` tags is a problem, not because there is a lot of event types (actually, there are 2 types), but because there is a lot of variations of what to render and I can't know them in advance. Imagine there is a page with ~20 components. To display a component, a long-running task should be executed (takes from 20ms to 5sec on average). And I have a method which iterates over ~20 tasks. Once a task is executed I send a message via a socket. So listing all possible options is not feasible... – Andrew Tobilko Nov 13 '19 at 15:57
  • For now, I trigger `p:remoteCommand` in my `onmessage` listener passing parameters from JS and reading them in my bean method via `getExternalContext().getRequestParameterMap()` and doing `Ajax.update(fetchedIds)`. It works fine, but there should be a better solution. – Andrew Tobilko Nov 13 '19 at 16:11