Call action methods in controller managed beans through javascript - jsf

In order to reducing the state I am trying to reduce the no of commandButtons on my webpages.(I had large no of commandButtons shown under a long list of 20 items (6*20 = 120 commandButtons)). Thus I am trying to figure out a way, through javascript by which I can pass parameters & call the action methods in the ManagedBean controller classes. Is there any way to call action methods from javascript & pass them parameters ?

Richfaces 3.2.0.GA and XHTML as mark up
You can use javascript to call an a4j:js method, which inturn calls action method from managed bean.
The param which you need to pass can be set to a hidden variable which when set will set the value to the java variable in your bean.
<script>
function onButtonClick(){
$("#yourValue").val("value");
actionListenerMethod();
}
</script>
<a4j:jsFunction name="actionListenerMethod"
actionListener="#{yourManagedBean.actionMethod}"
oncomplete="scriptOnComplete();">
</a4j:jsFunction>
<h:inputHidden id="yourValue"
value="#{yourManagedBean.yourValue}" />
Managed bean:
public void actionMethod(ActionEvent event){
if(yourValue == "something"){
/*your action goes here*/
}
}
Otherwise you can by-pass this hidden variable by use of action param
<script>
function onButtonClick(){
actionListenerMethod("value");
}
</script>
<a4j:jsFunction name="actionListenerMethod"
actionListener="#{yourManagedBean.actionMethod}"
oncomplete="scriptOnComplete();">
<a4j:actionparam name="param1"
assignTo="#{yourManagedBean.yourValue}" />
</a4j:jsFunction>
In the later case the action param might get set only after the manged bean gets completed, in this case you can use Action atribute to call your action method instead of an action listener.
This will help you to set the param and then call the action method.
<a4j:jsFunction name="actionListenerMethod"
action="#{yourManagedBean.actionMethod}"
oncomplete="scriptOnComplete();">
<a4j:actionparam name="param1"
assignTo="#{yourManagedBean.yourValue}" />
</a4j:jsFunction>

Related

Primefaces blockUi trigger by boolean value

How to trigger primefaces <p:blockUI> using boolean in backing bean? In this showcase, it requires a commandButton to trigger the the blockUI. What I want is block some part of the page base on a boolean in the backing bean. Is this possible? I tried setting the rendered attribute in the <p:blockUI> tag but it still won't work.
Here is my code:
<p:blockUI block="grid" rendered="#{bean.trueValue}"></p:blockUI>
<p:panelGrid id="grid">
-- content
</p:panelGrid>
One way is to call hide() and show() method of BlockUI from Managed Bean.
You can do that by using RequestContext:
RequestContext.getCurrentInstance().execute("widgetVar.show()");
Another is you can pass the variable to JavaScript function and then let the Javascript function take care of that for you.
onClick="func(#{elvariable})"
<script type="text/javascript">
function func(value)
{
if(value==something){
widgetVar.show();
}else{
widgetVar.hide();
}
}

p:button with onclick javascript hook

I'm using p:button with onclick action. (I can't move to p:commandButton, because of legacy outcome navigation in faces-config.xml and custom navigation history in db):
<p:remoteCommand name="unlock_tt" actionListener="#{ttEntityMBean.unlock()}"/>
<p:button value="#{msgs['button.ok']}" outcome="#{ttEntityMBean.navigationMenuItemToRedirect.navigationRule}" onclick="unlock_tt()"/>
Generated by primefaces javascript looks like
onclick="unlock_tt(); window.open(....)"
And after clicking button, unlock_tt() in browser initiated, but immediatly broken by page redirecting, so backed java method didn't execute.
Should I make unlock_tt() or java call async to be sure it will be executed before browser leaves page?
Upd: I'm thinking to use p:commandButton, if it is possible to get to-view-id programically, like in this question:
Programmatically get navigation case <to-view-id> from faces-config.xml by outcome
<p:commandButton action="#{ttEntityBean.unlock()}"/>
public String unlock() {
//some business logic
return OutcomeResolverHelper.getRuleFor(navigationMenuItemToRedirect.navigationRule)
}
This should reduce number of requests
I'm not sure this will work but can you try this :
Instead of :
<p:remoteCommand name="unlock_tt" actionListener="#{ttEntityMBean.unlock()}"/>
<p:button value="#{msgs['button.ok']}" outcome="#{ttEntityMBean.navigationMenuItemToRedirect.navigationRule}" onclick="unlock_tt()"/>
do:
<h:panelGroup>
<f:ajax event="click" listener="#{ttEntityMBean.unlock}"/>
<p:button value="#{msgs['button.ok']}" outcome="#{ttEntityMBean.navigationMenuItemToRedirect.navigationRule}" />
<h:panelGroup>
Don't forget to remove onclick and your remotecommand.
This should wrap a panelGroup around your button. PanelGroup implements ClientBehaviorHolder so it can get f:ajax tag in its children. Thus when you click on it it should trigger the listener.
The easiest way was migration from p:button to p:commandButton, which allows to execute some java-code in action method before redirect. The core is programmical translation of navigation rule, defined in faces-config.xml to base url, usable in explisit jsf-2.0 style:
//receive base url from <to-view-id> tag
public static String resolveOutcomeRule(String ruleName) {
FacesContext context = FacesContext.getCurrentInstance();
ConfigurableNavigationHandler configNavHandler = (ConfigurableNavigationHandler)context.getApplication().getNavigationHandler();
NavigationCase navCase = configNavHandler.getNavigationCase(context, null, ruleName);
return navCase.getToViewId(context);
}
//decorate it with faces-redirect=true and our custom navigation
public static String resolveOutcome(NavigationMenuItem item) {
return resolveOutcomeRule(item.getNavigationRule()) + "?faces-redirect=true&menu=" + item.getId();
}
//controller-method
public String cancelEditTT() {
super.unlock();
return FacesUtil.resolveOutcome(getNavigationMenuItemToRedirect());
}
//new jsf button:
<p:commandButton value="#{msgs['button.ok']}" action="#{ttEntityMBean.cancelEditTT}"/>
This solution provided 1-step redirect instead of 2-step old one.

Pass current selected row of p:dataTable to JavaScript function in p:ajax oncomplete

How can I pass current selected row to JavaScript function in <p:ajax oncomplete>?
<p:dataTable value="#{bolt.sites}" var="bolt" selection="#{bolt.selectedSite}" ...>
<p:ajax event="rowSelect" oncomplete="alert(#{bolt.selectedSite.name});" />
I have tried all: #{bolt.selectedSite.name}, #{bolt.name}.
EL expressions in oncomplete attribute are not evaluated after invoking the action. They are already evaluated while rendering the JavaScript code containing that ajax calling logic.
Your best bet is adding a listener method which adds the name as a callback parameter via RequestContext#addCallbackParam() which will then be available as a property of the implicit args object inside oncomplete context.
<p:ajax ... listener="#{bean.select}" oncomplete="alert(args.name)" />
public void select() {
String name = selectedSite.getName();
RequestContext.getCurrentInstance().addCallbackParam("name", name);
}
Unrelated to the concrete problem, you have a syntax error in your initial JavaScript attempt. The property name "name" suggests that it's a string. In JavaScript, all string values should be quoted. So your fictive solution would be oncomplete="alert('#{bolt.selectedSite.name}');"

Richfaces valueChangeEvent on input not working

I'm trying to use an richfaces inputNumberSlider or inputNumberSpinner.
The problem is I'm not able to update the values in my beans.
Here are the 2 solutions I tried:
1)
<rich:inputNumberSlider value="#{skinningBean.currentSkin.topBar.bannerXOffset}"
valueChangeListener="#{skinningBean.valueBannerXOffSetChangeListener}"
onchange="A4J.findForm(this).submit()">
</rich:inputNumberSlider>
In the bean:
public void valueBannerXOffSetChangeListener(ValueChangeEvent event) {
System.out.println("x value changed");
currentSkin.getTopBar().setBannerXOffset((Integer) event.getNewValue());
}
2)
<rich:inputNumberSpinner value="#{skinningBean.currentSkin.topBar.bannerYOffset}">
<a4j:ajax event="change" render="preview" oncomplete="initSlider()" />
</rich:inputNumberSpinner>
This should just call my setter in the bean. I havw written two setter one which takes a String and one which takes an Integer. None of them is called
Although I need an a4j supprt anyway to rerender my items, a working solution for number 2 would be preferred
Try the following first, once you get it working you can add the oncomplete part:
<rich:inputNumberSpinner value="#{skinningBean.currentSkin.topBar.bannerYOffset}">
<a4j:ajax event="onchange" render="preview" action="#{bean.valueBannerXOffSetChangeListener}" />
</rich:inputNumberSpinner>
Possible you will need to redefine your bean function to not receive parameters.
Reference:
https://community.jboss.org/message/588944#588944

How can I maintain param on ajax call? [duplicate]

This question already has answers here:
Retaining GET request query string parameters on JSF form submit
(2 answers)
Closed 6 years ago.
Whenever I make an ajax call, my URL param expires. The workaround I have done is to pass a param request inside every button like in:
<p:commandLink value="Submit" actionListener="#{mybean.dosomething}">
<f:param name="foo" value="#{mybean.bar}"/>
</p:commandLink>
However, in some scenarios I can't do the above workaround. For example when I'm using primefaces rowEditEvent:
<p:ajax event="rowEditCancel" listener="#{mybean.onCancel}"/>
The param expires when I make this ajax call and results in error before invoking #{mybean.onCance} as I'm reading datatable's data from the param in URL.
So how can I maintain the param value when I make such an ajax call?
PS: mybean is ViewScoped
Problem Extension:
The <o:form> has solved part of the problem, but now I can't send params inside the form for dynamic image streaming inside the table. See the following:
<p:dataTable value="#{mybean.data}" var="var">
<p:column headerText="Thumbnail">
<p:graphicImage value="#{streamer.thumbnail}">
<f:param name="id" value="#{var.id}"/>
</p:graphicImage>
</p:column>
</p:dataTable>
Streamer Bean (RequestScoped):
public StreamedContent getThumbnail() throws IOException {
FacesContext context = FacesContext.getCurrentInstance();
if (context.getRenderResponse()) {
return new DefaultStreamedContent();
}
else {
String string = context.getExternalContext().getRequestParameterMap().get("id");
Long id = Long.parseLong(idString);
MyImage img = (MyImage) service.find(MyImage.class, id);//get resource
StreamedContent sc = new DefaultStreamedContent(img.getInputStream(), "image/jpg", img.getName());
return sc;
}
}
Here string is always null and parameter is not passed resulting in error
Register it as a <f:viewParam>
<f:viewParam name="foo" value="#{mybean.bar}" />
and instead of <h:form>, use OmniFaces <o:form> with includeViewParams="true" (which uses under the covers a custom ViewHandler implementation which automatically collects all view parameters and appends them to the outcome of the getActionURL() method which is used as form action URL):
<o:form includeViewParams="true">
...
</o:form>
This way all view params are included in the form's action URL and will therefore end up as request parameters the usual way without the need to fiddle with <f:param> and being clueless inside <p:ajax> (and <f:ajax>).

Resources