Primefaces RequestContext scrollTo does not work - jsf

Primefaces v3.5
Trying to use RequestContext.getContext().scrollTo("") to scroll to my form programmatically at the end of an ajax request.
XHTML snippets:
<h:form id="genericMessagesForm">
<p:messages id="genericMessages" />
</h:form>
<p:commandButton id="testButton"
value="Test" process="#{cc.attrs.itemName}Final, #this"
actionListener="#{myBean.methodCalledByAjax()}" />
Bean:
public void methodCalledByAjax() {
List<String> updateTargets = new ArrayList<String>();
updateTargets.add("currentRecordForm");
updateTargets.add("genericMessagesForm");
RequestContext.getCurrentInstance().update(updateTargets);
RequestContext.getCurrentInstance().scrollTo("genericMessagesForm");
}
Update does work.
ScrollTo does NOT work (same ID!).
No server errors thrown.
No javascript console errors thrown.
Browsers tried: Firefox (latest), Chrome (latest), IE8.

Did you look in the documentation? Here's a cite from the RequestContext#scrollTo() javadoc:
scrollTo
public abstract void scrollTo(String clientId)
Scroll to a component after ajax request is completed.
Parameters:
clientId - Client side identifier of the component.
Look, it says client ID, not component ID. It makes also sense, the scrolling job is ultimately done by JavaScript via document.getElementById() and friends. That works only with a client ID.
For starters who haven't memorized the whole NamingContainer thing, an easy way to figure the right client ID is by looking at the JSF-generated HTML output via rightclick, View Source in webbrowser.
For a
<h:form id="genericMessagesForm">
<p:messages id="genericMessages" />
</h:form>
that's thus something like
<form id="genericMessagesForm" ...>
<div id="genericMessagesForm:genericMessages" ...>
...
</div>
</form>
So, fix the call accordingly:
requestContext.scrollTo("genericMessagesForm:genericMessages");
By the way, if the form contains solely the <p:messages>, then you can alternatively also just get rid of the whole form altogether. The <p:messages> is not an EditableValueHolder nor ActionSource component and does therefore not require to be placed in an UIForm component. This way you can keep using your initial attempt.
See also:
How to find out client ID of component for ajax update/render? Cannot find component with expression "foo" referenced from "bar"

Related

How can I change a bean property with a button

I'm trying to create a button that once clicked will change a property in a bean.
<h:commandButton type="button" action="#{loginBean.withdraw}" id="thousand" class="buttons" style="top:180px;left:570px;">
<f:setPropertyActionListener target="#{loginBean.withdrawAmount}" value="1000" />
</h:commandButton>
public class LoginBean {
int withdrawAmount;
This method only works when I omit the type="button" from the commandButton, but with the type="button" it doesn't work and I'm not sure why.
I need the type="button" to be there , is there any way to keep it and still make it work ?
There is an error in your facelet snippet:
There is no such attribute as class for <h:commandButton>. Possibly you meant styleClass.
As for the problem you have, you have to:
Either provide a setter method for the withdrawAmount property
public void setWithdrawAmount(int withdrawAmount) {
this.withdrawAmount = withdrawAmount;
}
and your facelet should look like:
<h:commandButton type="submit"
action="#{loginBean.withdraw}"
id="thousand"
styleClass="buttons"
style="top:180px;left:570px;">
<f:setPropertyActionListener target="#{loginBean.withdrawAmount}"
value="1000" />
</h:commandButton>
Or, you can get rid of the <f:setPropertyActionListener> and add a statement the changes the value of the withdrawAmount as a first line of the #{loginBean.withdraw} method.
In this case your facelet snippet should look like:
<h:commandButton type="submit"
action="#{loginBean.withdraw}"
id="thousand"
styleClass="buttons"
style="top:180px;left:570px;" />
and your LoginBean#withdraw() method should start with the statement, that changes the withdrawAmount value:
public String withdraw() {
this.withdrawAmount = 1000;
//the remaining logic.
}
Personally, I would prefer the first option.
More info:
< h:commandButton > tag reference
JSF Core Tag :setPropertyActionListener vs attribute vs param
The type is the entire reason why you're having this issue. I'm posting this answer because the accepted answer doesn't explain why you're experiencing the issue.
<h:commandButton/> is designed to work in 3 modes:
submit: This is the default mode that the button is set to. This mode sends an HTTP POST request to the server that triggers the JSF request processing lifecycle. It's only this mode that enables you to trigger backing bean methods(using the action or actionListener attributes).
button: This mode triggers a GET request in the application. As GET requests go, this mode is mostly suited for navigation, i.e. requesting another view or page. In this mode, there's no easy/straightforward way to execute backing bean code, or trigger the JSF request processing lifecycle. This is your current issue
reset: This mode simply resets the value of all input components within its enclosing <h:form/>
Reference:
JSF2 Command Button VDL
JSF redirect via commandButton
Difference between h:button and h:commandButton

commandButton inactive after ajax rendering

I have a problem with these two commandButton : Join and Leave.
I want to hide Join if I click on leave and vice-versa.
When I put ajax on false, there is no problem (but all the page is refresh and I don't find this optimal).
But when ajax attribut is on true with specific updating (cf comment in the code), the rendering is good but the new button whitch appear become inactive. If I click on it, nothing happens (well it's seems the actionListener trigger but the view is not refreshed, I have to manual refresh to see the difference)
Thanks for reading.
<h:form id="formWaitingList" rendered="#{connexion.connected}" >
<p:commandButton id="Join"
actionListener = "#{connexion.joinWaitingList()}"
rendered="#{!connexion.waiting}"
ajax="false"
<!-- ajax="true"
update="Join,Leave"-->
value="Join"/>
<p:commandButton id="Leave"
value="Leave"
ajax="false"
<!-- ajax="true"
udpate="Join,Leave"-->
rendered="#{connexion.waiting}"
actionListener ="#{connexion.leaveWaitingList()}" />
</h:form>
It seems that you're not entirely familiar with HTML/JavaScript. You know, JSF is basically a HTML/JavaScript(/CSS) code generator. Ajax updating works basically like this in JavaScript:
After sending the ajax request to JSF via XMLHttpRequest, retrieve a XML response which contains all elements which needs to be updated along with their client IDs.
For every to-be-updated element, use document.getElementById(clientId) to find it in the current HTML DOM tree.
Replace that element by new element as specified in ajax XML response.
However, if a JSF component has not generated its HTML representation because of rendered="false", then there's nothing in the HTML DOM tree which can be found and replaced. That totally explains the symptoms you're "seeing".
You basically need to wrap conditionally rendered JSF components in a component whose HTML representation is always rendered and then reference it instead in the ajax update.
For example,
<h:form>
...
<h:panelGroup id="buttons">
<p:commandButton ... update="buttons" rendered="#{condition}" />
<p:commandButton ... update="buttons" rendered="#{not condition}" />
</h:panelGroup>
</h:form>
See also:
Why do I need to nest a component with rendered="#{some}" in another component when I want to ajax-update it?

Opening a new window if condition true in managed bean

I want to implement a situation where the user enter a URL, and if a specified condition is true in my managed bean this URL will be opened in a new web page.
I found this possibility:
The “h:link” tag is useful to generate a link which requires to interact with the JSF “outcome” , but lack of “action” support make it hard to generate a dynamic outcome.
The “h:commandLink” tag is suck, the generated JavaScript is really scary! Not recommend to use this tag, unless you have a solid reason to support. But it supports the “action” attribute, which is what “h:link” lack of.
The “h:outputLink” is useful to generate a link which does not require to interact with the JSF program itself.
At last, it will be perfect if the “action” attribute is added into the “h:link“.
But I didn't find a way to launch the open web page from my managed bean after the condition is verified.
I'm using JSF2.0, Facelets and PrimeFaces 3.4.
To open the target in a new window using one of those link components, you need to specify target="_blank" attribute, but this will already open the target in a new window at the moment you click the link and does thus not depend on the response. You basically need to open the target in a new window at the moment the response has been arrived. The only way is returning a JavaScript window.open() call to the response so that it get executed in the webbrowser.
In standard JSF, you could just render JavaScript's window.open() conditionally.
<h:form>
<h:inputText value="#{bean.url}" />
<h:commandButton value="submit" action="#{bean.submit}">
<f:ajax execute="#form" render="#form" />
</h:commandButton>
<h:outputScript rendered="#{bean.valid}">window.open('#{bean.url}')</h:outputScript>
</h:form>
with
private String url;
private boolean valid;
public void submit() {
valid = validate(url);
}
// ...
In PrimeFaces, you could use RequestContext#execute() to specify JavaScript code which needs to be executed on complete of the response.
<h:form>
<p:inputText value="#{bean.url}" />
<p:commandButton value="submit" action="#{bean.submit}" />
</h:form>
with
private String url;
public void submit() {
if (validate(url)) {
RequestContext.getCurrentInstance().execute("window.open('" + url + "')");
}
}
// ...
Unrelated to the concrete problem: the ranty statements which you cited there are seemingly written by someone who know nothing about HTTP/HTML basics (limitations of GET vs POST and so on). Please take them with a good grain of salt.

p:commandButton does not fire action

Here is the problem: actionlistener does not want to be fired
#ManagedBean(name="hotelsController")
#SessionScoped
public class HotelsController implements Serializable {
public void requestHotelAvail(ActionEvent event) {
request = new Request(df.format(arrivalDate), df.format(departureDate));
}
}
and xhtml
<h:panelgroup id="rooms"/>
<h:form id="hotelSearch">
<p:commandButton actionListener="#{hotelsController.requestHotelAvail}" value="submit" update="rooms" />
</h:form>
I have tried everything I could search of changed #managedbean to #component set import to import javax.faces.event.ActionEvent;
But it still does not fire anything.
Form is in a p:accordion and when used with h:commandbutton it works fine
EDIT: sorry for mislead. rooms updates after click but actionListener is not fired. so rooms will not get any new data. Important code in requestHotelAvail needs to be fired before updating rooms and its not.
EDIT2: PrimeFaces 2.2.1 - I've read whole manual to primefaces but theres no explanation to this as I've done all that it states
I've tried using action instead of actionListener without ActionEvent but it never do anything. using <h:commandbutton action="#{hotelscontroller.requestHotelAvail}"/> works great but I want that ajax engine to refresh only that rooms panelgroup
UPDATE: Now it works. Form couldn't be in <p:accordion> but why and how to enable it there? Form now I'll work without it.
I suspect the different behavior from h:commandLink comes from ajax/non-ajax processing.
By default - if you don't use f:ajax - h:commandLink is non-ajax and entire page is rerendered. Primefaces p:commandLink is using ajax and you indicate rooms as component to be updated. In your case rooms is outside form so it should rather be addressed as :rooms (mind the colon) instead of just rooms.
update: have you tried ajax with h:commandLink? It would be:
<h:commandButton action="#{hotelscontroller.requestHotelAvail}" value="submit">
<f:ajax render=":rooms"/>
</h:commandButton>
Also I'm not that familiar with primefaces but maybe you can try to explicitly indicate the component to process with additional process="#this" - although I would assume this to be default as in basic library.
You try to inspect the response:
Open Chrome or Firefox -> Inspect Element -> Network and follow the ajax call.

JSF validation for client side injected elements

I know there is a property in asp.net (probably this EnableEventValidation of "<%# Page%> tag) .Which, once caused problem when i try to add select items to a component using javascript ,I want to know how jsf handling this. That is,
if i send a h:select* like below and client add a new item "option3 " to item list, is jsf detect this automaticly before update model values .
<h:selectOneMenu id="type"
value="#{foo.value}"
required="true"
requiredMessage="Type is required"
style="width:100px">
<f:selectItem value="option1}"/>
<f:selectItem value="option2}"/>
</h:selectOneMenu>
I think what you need to understand regarding JSF is that the client/server parts of the components are tightly coupled together. You are probably better off thinking of them strictly as one entity, and forget about fiddling with one side only, reverting to custom Javascript when that is the only solution left.
The other way to think of it is that the server side renders the client side, not vice versa! So whenever you need to update a component the update must be done on the server side first, which will propagate to the client side (the browser).
In your example the proper way to add and element to the select* items is to store the selectable items in a data structure within a bean (probably #ViewScoped), and then do a partial update via AJAX for the select* component or its container component, when the server side gets the chance to become aware of the changes and can update the client side properly as well.
Sure, you can hack your way through Javascript only, but then why use JSF? The whole point of JSF is to avoid the need for hacks like this.
Remember, JSF is not JSP, which is basically a println macro for html output. JSF stores the page components' representation on the server side, mirroring the browser's representation.
Check the Primefaces showcase for examples on how to do partial updates. More specifically this is the example you could be looking for. This is available in standard JSF2, for JSF 1.2 you must use a component library to get AJAX support.
You should not add the new option by JavaScript, but you should add the new option by JSF. JSF needs to know about the new option somehow in order to allow the submitted value. The new option really needs to be served by <f:selectItem(s)>. Otherwise you will face Validation error: Value not valid all the time when submitting the option value which is added by JS. This is after all just a safeguard of JSF to prevent clients from manipulating the request and submitting values which they are not supposed to submit.
The following kickoff example should work:
<h:form>
<h:selectOneMenu id="menu" value="#{bean.item}">
<f:selectItems value="#{bean.items}" />
</h:selectOneMenu>
<h:inputText id="newItem" value="#{bean.newItem}" />
<h:commandButton value="add" action="#{bean.addNewItem}">
<f:ajax execute="#this newItem" render="menu" />
</h:commandButton>
<h:commandButton value="submit" action="#{bean.submit}" />
</h:form>
with a #ViewScoped managed bean something like follows:
private String item;
private List<String> items = Arrays.asList("option1", "option2");
private String newItem;
public void addNewItem() {
items.add(newItem);
}
// ...

Resources