i'm trying to get a plain commandLink to work. Here is a code snippet of the page:
<div class="item-single">
<h:graphicImage value="image/screenshots/#{collectionListBean.collectionListTeaser[0].screenshot}" alt="Screenshot #{collectionListBean.collectionListTeaser[0].title}"/>
<div class="item-title">
<h:form id="teaser0">
<h:commandLink value="#{collectionListBean.collectionListTeaser[0].title}" action="#{collectionBean.showCollection(collectionListBean.collectionListTeaser[0].id)}" />
</h:form>
</div>
<div class="item-description">
<p>
<h:outputText value="#{collectionListBean.collectionListTeaser[0].persons.get(0).person.getFullName()}" />
</p>
</div>
</div>
The title is displayed correctly, so the backing bean and the list is available and accessible. CollectionBean is also available and accessible. The list has a fixed size and is used inside a javascript gallery which is the reason why i didn't use ui:repeat or h/p:dataTable elements.
I have also checked BalusC'S List of common problems
The action is not being invoked in the backing bean, I get following javascript error on the browser console:
Uncaught TypeError: Cannot read property 'teaser0:_idcl' of undefined
Here is the relevant code of the backing bean (collectionBean):
#Named("collectionBean")
#Scope("access")
#ViewController(viewIds = {ViewIds.EDIT_COLLECTION, ViewIds.SHOW_COLLECTION, ViewIds.EDIT_COLLECTION, ViewIds.METADATA_COLLECTION_ADMIN, ViewIds.EDIT_COLLECTION_EXISTING, ViewIds.COLLECTION_LIST, ViewIds.HOME})
public class CollectionBean extends CollectionBeanBase {
.
.
.
public String showCollection(long id) {
//Check if user is admin, if yes, allow to edit metadata
Authentication auth=SecurityContextHolder.getContext().getAuthentication();
this.collection = collectionService.findById(id);
if (!(auth instanceof AnonymousAuthenticationToken)){
role=auth.getAuthorities().iterator().next().getAuthority();
if(role.equalsIgnoreCase("ROLE_ADMIN")) {
this.collection.setEdit_flag(true);
return ViewIds.EDIT_COLLECTION;
}
}
return ViewIds.SHOW_COLLECTION;
}
Does anyone have an idea what the problem might be? Any hint is highly appreciated! thank you guys in advance!
This is commandLink then why are you passing value in method.
Means you can use
<f:param name="id" value="#{collectionListBean.collectionListTeaser[0].id}"/>
you can easily get that value in action.
like
public String showCollection() {
FacesContext fc = FacesContext.getCurrentInstance();
Object id = fc.getExternalContext().getRequestParameterMap().get("id");
System.out.println(id);
return ViewIds.SHOW_COLLECTION;
}
i think this is best way to do it.
I rearranged the element to wrap all of the div's affected by the jQuery gallery and now it works like a charm.
Related
I have a p:commandLink in my xhtml with the value toggling between "Show"/"Hide".
Is there any way by which I can get the value of this commandlink from the backing bean?
I mean, I want to know what value the command link is showing currently i.e. Show/Hide?
To the point, the invoking component is just available in ActionEvent argument:
<h:commandLink id="show" value="Show it" actionListener="#{bean.toggle}" />
<h:commandLink id="hide" value="Hide it" actionListener="#{bean.toggle}" />
with
public void toggle(ActionEvent event) {
UIComponent component = event.getComponent();
String value = (String) component.getAttributes().get("value");
// ...
}
However, this is a poor design. Localizable text should absolutely not be used as part of business logic.
Rather, either hook on component ID:
String id = (String) component.getId();
or pass a method argument (EL 2.2 or JBoss EL required):
<h:commandLink id="show" value="Show it" actionListener="#{bean.toggle(true)}" />
<h:commandLink id="hide" value="Hide it" actionListener="#{bean.toggle(false)}" />
with
public void toggle(boolean show) {
this.show = show;
}
or even just call the setter method directly without the need for an additional action listener method:
<h:commandLink id="show" value="Show it" actionListener="#{bean.setShow(true)}" />
<h:commandLink id="hide" value="Hide it" actionListener="#{bean.setShow(false)}" />
As #BalusC suggested, your approach is not a good solution. But if you really want to do that, you can bind the component (p:commandLink) to your backingbean, as seen in What is the advantages of using binding attribute in JSF?.
After the component was bound, you can access the value attribute from the p:commandLink.
I have written a piece of code to put two pairs of radio button in a *.xhtml page of a JSF project built in JSF2.0, Jboss As 7.1.1 final and JDK 6.0, PrimeFaces 3.4.2.
<h:panelGrid columns="2">
<h:selectOneRadio value="#{calendarBean.radioFirst}">
<f:selectItem id="morning" itemValue="morning" itemLabel="Morning"/>
<f:selectItem id="afternoon" itemValue="afternoon" itemLabel="Afternoon"/>
</h:selectOneRadio>
<h:selectOneRadio style="padding-left: 170px" value="#{calendarBean.radioSecond}">
<f:selectItem id="noon" itemValue="noon" itemLabel="Noon"/>
<f:selectItem id="endofday" itemValue="endofday" itemLabel="End Of Day"/>
</h:selectOneRadio>
</h:panelGrid>
The Bean is:
private String radioFirst="morning";
private String radioSecond="endofday";
public String getRadioFirst() {
return radioFirst;
}
public void setRadioFirst(String radioFirst) {
this.radioFirst = radioFirst;
}
public String getRadioSecond() {
return radioSecond;
}
public void setRadioSecond(String radioSecond) {
this.radioSecond = radioSecond;
}
I have written a method to invoke on a Action Event where I want to have the values of the radio button selected. when the method invokes I get the value of the radio buttons as "morning" and "endofday" as these two are the initial values of the bean variables.
private String radioFirst="morning";
private String radioSecond="endofday";
But if I change the radio button options, I don't get the updated values, its the same old initial values. How can I get the changed values? Please help!
Three things
Don't use the session scope for this usage scenario. This will go completely wrong when your users open the same page in more than one tab. Use request scope or view scope.
Use a regular action instead of an action listener, and don't provide the radio button values as attributes. This makes no sense. The selectOneRadio components will set the updated values on your backing bean. When your action method is invoked, you will have access to those values via the instance fields of your bean.
Leave out the window.reload. If you need a full page refresh after the action, set ajax to false on the p:commandButton or use an h:commandButton.
You should modify your action button like this :
<p:commandButton actionListener="#{userLeaveBean.addAppliedLeave}" styleClass="apply_button" value="Create Leave">
<f:attribute name="userId" value="#{employee.name}"/>
</p:commandButton>
As #MikeBraun suggested, remove the window.reload(). If you want to refresh something, you could do it by using the update attribute from the p:commandButton.
And modify your bean according to this :
#ManagedBean
#SessionScoped // Could probably be moved to #RequestScoped or #ViewScoped
public class UserLeaveBean
{
#ManagedProperty(value="#{calendarBean}")
CalendarBean calendarBean;
public void setCalendarBean(CalendarBean calendarBean)
{
this.calendarBean = calendarBean;
}
public void addAppliedLeave(ActionEvent event)
{
System.out.println("Radio 1 : " + calendarBean.getRadioFirst());
System.out.println("Radio 2 : " + calendarBean.getRadioSecond());
}
}
The ManagedProperty will get the other bean accessible for you by injecting it inside the current one. Use the proper scope, probably you are using SessionScoped because you are using window.reload().
Important : the ManagedProperty bean must be at least scoped the same length as the other bean.
Read more :
Injecting Managed Beans in JSF 2.0
PrimeFaces Showcase - commandButton
I am using PF3.5+JSF2.1.22 and in my web application i am using Primefaces Captcha component. I am getting some weird issue in capcha component,i used captcha component like this in application
<p:captcha id="captcha" label="Captcha" theme="white" />
And i have a PF command page to submit the values to bean
<p:commandButton id="clear" value="Clear" update="captcha" styleClass="kuberbutton" />
When i am using button like above after form submit if any validation issue and other issue coming and age is loading again then Captcha is not visible in page any more but when i am using ajax="false" in PF button then it is working,is this is behavior this component will work i have to do ajax="false"? I checked the PF website they also did same thing Primefaces Captcha
Captcha component in Primefaces currently does not support ajax behavior , that why you must use ajax="false" in your <p:commandButton , you page must be fully reloaded for the captcha to work properly...
If you must have the ajax behavior you could use some other third party solution...
Haven't tried the following, but it might help with ajax issues:
recaptcha - AJAX AP
Displaying reCAPTCHA Without Plugins
How can I load a reCaptcha form using jQuery/AJAX while leaving the reCaptcha scripts in place?
As already said Primefaces Captcha component can't be updated by ajax request. But there is a simple solution - update everything but not Captcha component itself.
Your XHTML:
<h:form id="myForm">
<h:panelGroup id="updateFormAllValuesButNotCaptcha">
Name: <p:inputText id="name" value="#{captchaBean.name}" required="true"/>
<br/>
Comment: <p:inputTextarea id="comment" value="#{captchaBean.comment}" required="true"/>
<br/>
</h:panelGroup>
<p:captcha/>
<p:commandButton value="click me" update="updateFormAllValuesButNotCaptcha"
actionListener="#{captchaBean.someAction}" oncomplete="Recaptcha.reload()"
onerror="Recaptcha.reload()"/>
</h:form>
<p:messages globalOnly="false" autoUpdate="true"/>
Your backing bean:
#ManagedBean
#ViewScoped
public class CaptchaBean implements Serializable {
private String name;
private String comment;
public String getComment() { return comment; }
public void setComment(String comment) { this.comment = comment; }
public String getName() { return name; }
public void setName(String name) { this.name = name; }
public void someAction() {
FacesMessage msg = new FacesMessage(FacesMessage.SEVERITY_INFO, "Done", "");
FacesContext.getCurrentInstance().addMessage(null, msg);
}
}
Note that I am updating updateFormAllValuesButNotCaptcha panel which contains all form input fields but not Captcha itself. It is also important to notice that Captcha can't be reused, so you have to reload it always when ajax request has been completed or ended with error.
What you update after commandButton's action succeeded is up to you. You can hide form (do not render it) and show only confirmation message to make sure user won't try to send comment again.
What I'm trying to achieve is very similar to the one posted in the following link.
How to save an array in JSF with ui:repeat + h:inputText + managed bean?
I'm particularly fascinated with the answer provided by Arjan Tijms in the link above however what I want to achieve is slightly different. Consider the following code snippets.
The bean
import javax.annotation.PostConstruct;
import javax.inject.Named;
import javax.enterprise.context.RequestScoped;
#RequestScoped
#Named
public class MyBean {
List<String> choices;
public List<String> getChoices() {
return choices;
}
#PostConstruct
public void initChoices() {
choices= new ArrayList<String>();
}
public String save() {
// should save all the choices into some repository
return "";
}
}
and the facelet page
<html xmlns="http://www.w3.org/1999/xhtml"
xmlns:h="http://java.sun.com/jsf/html"
xmlns:ui="http://java.sun.com/jsf/facelets">
<h:body>
<h:form>
<ui:repeat value="#{myBean.choices}" varStatus="status">
<h:inputText value="#{myBean.choices[status.index]}" />
</ui:repeat>
<h:commandButton value="Save" action="#{myBean.save}" />
</h:form>
</h:body>
</html>
The thing is, this will work if we have some initial data in the list at the beginning. What about situations where the initial list will be empty?
The ideal solution which I'm looking for is to have 1 h:inputText for each choice and when save button is clicked, all choices in each h:inputText is then added to the choices list. I've searched high and low but can't seem to find any hints on how this can be done.
If JSF 2 really doesn't support this, I guess I'll have to use the ugly way with just one h:inputText and use a converter to convert to and from a list but I'm still hoping that an ideal solution can be found.
Hopefully someone from stackoverflow can shed a light in the right direction for me.
Just add an "add" button which adds a new String to the list.
<ui:repeat value="#{myBean.choices}" varStatus="status">
<h:inputText value="#{myBean.choices[status.index]}" />
</ui:repeat>
<h:inputText value="#{myBean.newChoice}" />
<h:commandButton value="Add" action="#{myBean.add}" />
<h:commandButton value="Save" action="#{myBean.save}" />
with
private String newChoice;
public void add() {
choices.add(newChoice);
newChoice = null;
}
// ...
Note that this only works if bean is put in view scope. A request scoped one would be constructed on every request and hereby recreate the list everytime.
I'm building on BalusC's solution to highlight and focus fields in JSF. My plan is to output a JSON array with ids and then have a method be called which will process this array. This works fine when I don't use <f:ajax/>
Here is my phase listener solution:
public void beforePhase(PhaseEvent event) {
FacesContext facesContext = event.getFacesContext();
List<String> highlightFields = new ArrayList<String>();
Iterator<String> highlightFieldsItr = facesContext
.getClientIdsWithMessages();
while (highlightFieldsItr.hasNext()) {
StringBuilder sb = new StringBuilder();
sb.append("#");
sb.append(highlightFieldsItr.next().replaceAll(":", "\\\\:"));
highlightFields.add(sb.toString());
}
JSONArray jsonHighlightFields = new JSONArray(highlightFields);
facesContext.getExternalContext().getRequestMap()
.put("errorFields", jsonHighlightFields.toString());
}
Basically this would produce errorFields value with something like ["#some\:id1", "#some\id2"]. Then I can do something like this in my root layout file:
<script>
var errorFields = ${errorFields}; // This will xlate to ["#some\\:id1", "#some\\:id2"
$(document).ready(function(){
processInputErrors(errorFields);
});
</script>
With a processInputErrors function like this:
function processInputErrors(ids) {
for (id in ids) {
if (focus == false) {
jQuery(ids[id]).focus();
focus = true;
}
jQuery(ids[id]).addClass('input-error');
}
}
However, I need to somehow obtain this list in the function which gets called on success of an ajax post.
Now f:ajax does have the onevent attribute and this function does get called, but I'm not sure exactly what it gets passed. How would I be able somehow pass the invalid Ids from the phase listener to this function? It seems to be passed an object which represents the HTMLInputElement?
<f:ajax event="change" onevent="test" render="test test_msg" immediate="true" />
Happy to hear about alternative suggestions or ideas. The goal is basically to focus and highlight the field(s) which are invalid not only on a full post-back but also when using f:ajax.
Thanks!
That article was more targeted on JSF 1.x. JSF 2.x offers now a lot of advantages of which the following are beneficial for your particular requirement:
You can refer the current component in EL by #{component}. In case of input components this is the UIInput which in turn has an isValid() method. This could be used in styleClass attribute.
You can use <f:ajax> to re-render parts of the view, also <script> elements.
1+1 is...
<h:inputText id="input1" value="#{bean.input1}" required="true" styleClass="#{component.valid ? '' : 'error'}">
<f:ajax render="#this input1message focus" />
</h:inputText>
<h:message id="input1message" for="input1" />
...
<h:inputText id="input2" value="#{bean.input2}" required="true" styleClass="#{component.valid ? '' : 'error'}">
<f:ajax render="#this input2message focus" />
</h:inputText>
<h:message id="input2message" for="input2" />
...
<h:panelGroup id="focus"><script>jQuery(":input.error:first").focus();</script></h:panelGroup>
No need for a PhaseListener anymore. You could if necessary wrap the input markup boilerplate in a composite component or a tag file.
Back to your concrete question about the onevent attribute, check this answer: JSF 2: How show different ajax status in same input?