Calling Managed Bean Method From JavaScript
You have a few options. If you are using JSF 2.0 you can build a composite component around these area tags.
The easiest way however would be to invoke a hidden JSF input button.
<h:commandButton id="hdnBtn" actionListener="#{personBean.method}" style="display: none;" />
This will render as an input
HTML element on the page that you can access from Javascript and invoke its click
event.
onclick="jQuery('#form:hdnBtn').click();"
How to call JSF backing bean method using javascript only when The page is loaded
As it turned out you actually want to have a client side cache in localStorage
and prevent business logic invocation if that client side cache is valid you
have to go the AJAX way:
I suggest to implement a javascript rendered conditionally which updates the local storage only if needed:
<h:panelGroup id="updateLocalStorageScript" style="display: none;">
<h:outputScript rendered="#{villeBean.updateLocalStorage}">
localStorage.setItem('date',date);
localStorage.setItem('ville', #{villeBean.villesList});
</h:outputScript>
</h:panelGroup>
The update can be triggered by a command action as proposed here: How to invoke a JSF managed bean on a HTML DOM event using native JavaScript?
<h:form id="frmHidden" style="display: none;">
<h:commandButton id="cmdDoUpdateLocalStorage" action="#{villeBean.doUpdateLocalStorage()}">
<f:ajax execute="@this" render=":updateLocalStorageScript" />
</h:commandButton>
</h:form>
Of course you can also use p:remoteCommand
, the OmniFaces solution or other suggestions proposed in above QA.
This command action leads to the javascript being rendered and initializes the list value by invoking your business logic only once.
@ManagedBean (name="villeBean)"
@ViewScoped
public class Villes {
private boolean updateLocalStorage;
private String villesList;
public void doUpdateLocalStorage() {
updateLocalStorage = true;
villesList = dao.listeVilles();
}
public boolean isUpdateLocalStorage() {
return updateLocalStorage;
}
public String getVillesList() {
return villesList;
}
}
Trigger that command from within your javascript conditional blocks:
if(localStorage['ville'] == null || localStorage['date']==null){
document.getElementById('frmHidden:cmdDoUpdateLocalStorage').onclick();
}
else{
var oldDate = new Date(localStorage['date']).getTime();;
var currentDate = new Date().getTime();
var distance = currentDate - oldDate ;
var days = Math.floor(distance / (1000 * 60 * 60 * 24));
if (days >= 15){
document.getElementById('frmHidden:cmdDoUpdateLocalStorage').onclick();
}
}
JSF comandButton execute action, then js function with bean value as a parameter
You may invoke JS code from Java, this execute when the response is rendering. View: https://www.primefaces.org/showcase/ui/misc/requestContext.xhtml
In action method Java you can coding:
PrimeFaces.current().executeScript("alert('This onload script is added from backing bean.')");
How to call managed bean methods with parameters via JavaScript
Just to add to Kishor's (halfway) answer, you need to have a to-be-updated component in your view (popup window as you call it) and ajax-update it after the request has been successfully completed.
You can use remote command to send the AJAX request with an extra parameter attached and ajax-update the JSF component responsible to be a popup window. Like so (for PrimeFaces 3.x):
<p:remoteCommand name="myRemote" actionListener="#{myBean.listen}"
update="dialog" oncomplete="dlg.show()" />
...
<div onclick="myremote([{name:'poi_id', value:poi_id}]);">...</div>
...
<p:dialog id="dialog" widgetVar="dlg">
<h:outputText value="#{myBean.address}" />
...(display other information)
</p:dialog>
with
String address;
public void listen(){
String poi_id = FacesContext.getCurrentInstance().getExternalContext().getRequestParameterMap().get("poi_id");
address = getAddress(poi_id);
}
The alternative to using a remote command is to have a hidden form with a hidden input that will be used to transmit the parameter to the backing bean, that could be separated from other beans to handle the retrieval of necessary information based on your poi_id
:
<h:form id="poi-form" styleClass="invisible">
<h:inputHidden id="poi" value="#{poiBean.poi}" />
<p:commandButton id="info" action="#{poiBean.info}"
update="dialog" oncomplete="dlg.show()" />
</h:form>
<div onclick="document.getElementById('poi-form:poi').value = poi_id;
document.getElementById('poi-form:info').click();">...</div>
...
<p:dialog id="dialog" widgetVar="dlg">
<h:outputText value="#{poiBean.address}" />
...(display other information)
</p:dialog>
with
@ManagedBean
@RequestScoped
public class PoiBean {
private String poi;//getter+setter
private String address;//getter
//other properties
public void listen(){
address = getAddress(poi);
//other properties
}
}
interrupt a Bean-method by calling a javaScript function?
Disclaimer: Code in the answer will contain untested code in PrimeFaces flavour and 'pseudo code'. Since I do not use/run IceFaces nor do I have the intention to, I cannot (will not) test the code and will only provide the PrimeFaces counterparts as an (untested) example
Answer
You seem to be stuck trying to get a technical solution to work that cannot work. JSF cannot 'pause' things and will only return data at the end of the bean method that is called. You are most likely mislead by the statement in the IcesFaces documentation
"Send immediately Javascript code to the client for evaluation and execution"
This cannot work due to the way JSF works and it is sort of not really good English. The developers should have stated something like
"Send Javascript code to the client at the end of the method call for immediate evaluation and execution"
The immediate means that it is not some <script> .... </script>
that gets added to the page and that can be executed again and again by e.g. calling a function that is defined in the script. It does not mean you cannot call existing javasript functions (ones that are already in your DOM) from the returned script (effectively that is what we will be using)
So how to solve your problem. Start by breaking the method down in two, lets call them step1 and step2
void step1() {
// Do things
// return javascript
}
void step2() {
// Do other things using values that will be posted from the client by javascript
}
How to return javascript/call javascript from a bean is an existing Q/A here in Stackoverflow. For the IcesFaces counterpart I refer to their documentation. A PrimeFaces example is
PrimeFaces.current().executeScript("alert('This onload script is added from backing bean.'); clientSideFunction();");
But at the end of the javascript you want to call a server side method in a bean from javascript. The opposite of what you need in step one.
A PrimeFaces example being
<p:remoteCommand name="clientSideFunction" action="#{bean.step2}" />
And in since in calling step2()
you want to pass parameters to the bean, you need to implement this as well.
clientSideFunction([{name:'x', value:10}, {name:'y', value:20}]);
You can use javascript variables in there (e.g. a complete json string in a variable) and need to process these variables (especially see the 'update' at the end)
Related Topics
How to Decide When to Use Node.Js
Check If an Element Is Present in an Array
Why Is Console.Log() Considered Better Than Alert()
Problem in Redirecting Programmatically to a Route in React Router V6
How to Async Await in React Render Function
Redirect a State to Default Substate with Ui-Router in Angularjs
How to Expose Iframe's Dom Using Jquery
What Does $(Function() {} ); Do
Setting Query String Using Fetch Get Request
How to Convert Blob to File in JavaScript
How to Set Time Delay in JavaScript
Coordinating Parallel Execution in Node.Js
Safari 3Rd Party Cookie Iframe Trick No Longer Working
Communication Between Sibling Components in Vue.Js 2.0
What Is the Cleanest Way to Get the Progress of Jquery Ajax Request