EL: cannot access property method - jsf

I have my database whit a BLOB field named 'avatar' in which I store the user's photo. This field is represented in my JPA entity as a byte[]. I want to render the 'avatar' element only if the array has a positive length, but i get the next exception from javax.servlet.FilterChain.doFilter() :
"Exception: Method length not found"
This is the code:
<o:graphicImage id="avatar"
value="#{loginView.user.avatar}"
dataURI="true"
rendered="#{loginView.user.avatar.length()>0}"
/>
If I check the length from the backing bean, returning a Boolean to the EL, it works and renders the image, but I need to preserve the backing code unaltered, that's why I need to do the checking from my xhtml.
Thanks.
edit: rendered="#{not empty loginView.user.avatar}" is not working, that's why I had to move to another option.

Try using JSTL. Taglib namespace:
xmlns:fn="http://java.sun.com/jsp/jstl/functions"
Usage:
<o:graphicImage id="avatar"
value="#{loginView.user.avatar}"
dataURI="true"
rendered="#{fn:length(loginView.user.avatar) > 0}"/>

Length is not a method but property of array. Try to make a method inside loginView bean which will return something like this.
public boolean isAvatarLoaded() {
return this.user.avatar.length > 0;
}
<o:graphicImage id="avatar"
value="#{loginView.user.avatar}"
dataURI="true"
rendered="#{loginView.isAvatarLoaded()}"
/>

Related

JSF PrimeFaces rendering components

Let's say I have a simple method that, like this:
public String test()
{
return "hello";
}
Now let's say I have the following PrimeFace component:
<p:fieldset styleClass="containers" rendered="#{controller.test()}">
<h2>Testing</h2>
<p:outputLabel for="test" value="Test" />
<p:inputText id="test" />
</p:fieldset>
The method above returns "hello". I would like to dynamically show and hide that fieldSet by comparing the returned value of that method to a field of one of my beans. For instance, on the rendered parameter, I would like to do something like: controller.test() != "some variable" which would return true or false. Am I allow to do that? If not, what is the way of doing it?
Basically the goal is to dynamically show and hide some container by comparing the returned value of a method with a bean property.
Look Like you misunderstood rendered
The rendered Attribute
A component tag uses a Boolean EL expression, along with the rendered
attribute, to determine whether or not the component will be rendered.
If you will check above definition you will know what exactly is the use of this attribute.
More you can see below
The rendered attribute which uses Boolean EL expression indicates
whether a component is currently visible or not. The property is
useful when you want to hide components for specific users or based on
condition. The default value of rendered attribute is true.
<h:outputText value=”mapping” rendered=”Boolean EL expression” />
For example, the commandLink component in the following section of a page is not rendered if the cart contains no items:
<h:commandLink id="check"
...
rendered="#{cart.numberOfItems > 0}">
<h:outputText
value="#{bundle.CartCheck}"/>
</h:commandLink>
With your concrete problem you can do like this
Make a String variable call value
Now create get/set methods for above variable
Now in your test method you can add
public void test(){
value="hello";
}
Bur remember you have call test() method of page load
Now in your Xhtml or Jsf or Jsp page
rendered="#{controller.value != 'hello'}"
Or better way create a Boolean variable and do all the magic of hide and show the component

Use JSF form to create an object with a list of other objects

I am using JSF 2 with Glassfish 4. I would like to create an object that has a collection of objects as one of its fields. When searching, I can only find ways to display a collection field in a JSF form. Here I want the opposite: allow the user to populate this collection while creating the parent object. Simplified example below:
Parent Object: Account
public class Account {
private String accountName;
private List<Order> orderList = new ArrayList<Order>();
public String save() {
System.out.println(accountName);
System.out.println(orderList);
return "";
}
// Constructors, getters and setters below.
}
Child Object: Order
public class Order {
private String orderName;
private Integer orderCost;
// Constructors, getters and setters below.
}
JSF Page Body
The idea for the form was taken from BalusC's answer here.
<h:body>
<h1>Create Account</h1>
<h:form>
<h:panelGrid>
Account Name:
<h:inputText value="#{account.accountName}" />
<ui:repeat value="#{account.orderList}" varStatus="loop">
Order Name:
<h:inputText value="#{account.orderList[loop.index]}" />
Order Cost:
<h:inputText value="#{account.orderList[loop.index]}" />
</ui:repeat>
</h:panelGrid>
<h:commandButton action="#{account.save}" value="Create" />
</h:form>
</h:body>
I run into a few problems:
It's impossible for me to have a set number of Orders displayed. (ex: max 5 per new account). An input field is only displayed if the List already has some objects. This makes sense, but I would like to present the user with X blank lines they can fill in.
I am unable to expose both the orderName and orderCost fields at once to the user.
Later on I would like to add a commandButton that adds another row of inputText fields in the UI so the user can add however many orders to an account as they want.
Any help greatly appreciated. Happy to answer questions for anything I missed. Thank you!
After BalusC's help I made the following changes and I now have the behaviour that I want:
// Prop up the array so the desired number of fields appears in the UI
#PostConstruct
public void prepare() {
orderList.add(new Order());
orderList.add(new Order());
orderList.add(new Order());
}
Iterate through the list of empty Order objects. No data is disabled since all field values in the Order objects are null. Also, since I created the objects in #PostConstruct, the user's changes are easily saved on Submit.
<ui:repeat value="#{account.orderList}" var="order">
Order Name:
<h:inputText value="#{order.orderName}" />
Order Cost:
<h:inputText value="#{order.orderCost}" /><br/>
</ui:repeat>
As to preparing a fixed amount of items and adding a new item, just add a new item to the list.
orders.add(new Order());
Do this in #PostConstruct to prepare the items on page load and do the same in "Add" button.
As to accessing properties, you don't need the varStatus/index trick as you've there a collection of mutable objects, not a collection of immutable objects (where the question you found was all about).
<ui:repeat value="#{bean.orders}" var="order">
<h:inputText value="#{order.name}" />
<h:inputText value="#{order.cost}" />
</ui:repeat>
If you really insisted to, you could have done #{bean.orders[loop.index].name}, but as said, this is unnecessary.

Dynamic allowed types in PrimeFaces fileUpload

My allowedTypes in PrimeFaces p:fileUpload are not static.They depend on some parameter which is passed as request parameter to the page. So how to change allowedTypes dynamically according to that request parameter.
I just tried it with defining the allowedTypes via a bean property and that is working for me.
So define a allowedTypes property in you bean
public String getAllowedTypes() {
return "/(gif|png)$/";
}
and call it in your page
<p:fileUpload fileUploadListener="#{fileUploadView.handleFileUpload}" mode="advanced" dragDropSupport="false"
update="rocomessages" sizeLimit="100000" fileLimit="3" allowTypes="#{fileUploadView.allowedTypes}" />
I have another idea. Create a String function with parameter(s), this can be used when the types must be dynamics.
This could be the String function in your Bean:
public String getAllowedTypes(String someData) {
if (value.equals("My special types")) {
return "/(\\.|\\/)(json)$/";
}
return "/(\\.|\\/)(ZIP|zip)$/";
}
and, like this, you call ir in the page:
<p:fileUpload allowTypes="#{MyBean.allowedTypes(MyBean.anotherString)}" />
Note: you can use Switch instead of IF in getAllowedTypes function, this must be understand for another uses.

In JSF2.0, how do I write out cookies in facelets?

I know how to write out individual cookies from facelets:
JSF:
<h:outputText value="#{facesContext.externalContext.requestCookieMap['TESTCOOKIE'].value}" />
Outputs:
MyCookieValue
I have been able to write out map, but the output is not the values but a reference to the value.
JSF:
<h:outputText value="#{facesContext.externalContext.requestCookieMap}" />
Output:
{DEFAULTUSERNAME=javax.servlet.http.Cookie#36a236a2,
TESTCOOKIE=javax.servlet.http.Cookie#36b436b4,
JSESSIONID=javax.servlet.http.Cookie#36d836d8}
You don't need such a long value expression to access your cookies in JSF 2.0, there is an implicit object named cookie which references the cookie map and it's equivalent to facesContext.externalContext.requestCookieMap.
So, following code:
<h:outputText value="#{cookie['TESTCOOKIE'].value}" />
should output the same as:
<h:outputText value="#{facesContext.externalContext.requestCookieMap['TESTCOOKIE'].value}" />
Now, if you want to iterate through all of them, my recommendation is to use backing bean:
#RequestScoped
#ManagedBean(name = "triky")
public class TrikyBean {
public List getCookies() {
FacesContext context = FacesContext.getCurrentInstance();
Map cookieMap = context.getExternalContext().getRequestCookieMap();
return new ArrayList(cookieMap.values());
}
}
And then use it like this
<ui:repeat value="#{triky.cookies}" var="ck">
#{ck.name}: #{ck.value}<br/>
</ui:repeat>
Clarification: This comes from the fact that the <ui:repeat /> tag will only accept java.util.List in its value attribute, otherwise it will create its own ListModel with just one element inside. Besides, the collection given by the default implementation of the values() method in a java.util.Map is not a java.util.List but a java.util.Set, so, the <ui:repeat/> tag was using that set as the only element of its own list model and when iterating through that list model the number of elements was just one and none of them were actually cookies.
Maps have a values() method that returns a collection of all elements. I think you need a stronger EL engine than the default to do method invocation outside of getters to do that though, like JBoss EL or JUEL (both of which i strongly recommend for any java ee 6 project).
The alternative is doing method invocation in java and supplying a getter like this:
myBean.java
public Collection getCookies(){
return FacesContext.getCurrentInstance().getExternalContext().getRequestCookieMap().values();
}
And iterating over the collection in your markup
<ui:repeat value="#{myBean.cookies}" var="cookie">
<p>#{cookie.name}: #{cookie.value</p>
</ui:repeat>
Haven't tried this out but something similar will work. You might have to replace the Collection with a List, not sure if ui:repeat supports Collections.
EDIT: as per the comment below, you could try this:
<ui:repeat value="#{facesContext.externalContext.requestCookieMap.values()}" var="cookie">
<p>#{cookie.name}: #{cookie.value</p>
</ui:repeat>

JSF Temporary Variable

Is there a way to temporarily save the value of calcuation in a JSF page?
I want to do the following without calculating twice:
<h:outputText value="#{complexModel.currencyAmount.currency}">
<h:outputText value="#{complexModel.currencyAmount.amount}">
I've tried using the alias bean but I get an error saying java.lang.IllegalArgumentException - row is unavailable.
e.g.
<t:aliasBean id="bean" alias="#{bean}" value="#{complexModel.currencyAmount}">
<h:outputText value="#{bean.currency}">
<h:outputText value="#{bean.amount}">
</t:aliasBean>
Thanks.
Two ways (at least):
Using lazy-init field of your complexModel. something like:
private Currency currencyAmount;
public Currency getCurrencyAmount() {
if (currencyAmount == null) {
currencyAmount = calculateCurrencyAmount();
}
return currencyAmount;
}
Using the JSTL <c:set> tag:
(the namespace first)
xmlns:c="http://java.sun.com/jstl/core"
then
<c:set var="varName" value="#{complexModel.currencyAmount}" />
And then the calculated value will be accessible through #{varName}.
In JSF 2.0,you can use <ui:param/> which it's powerful.
<ui:param name="foo" value="#{zhangsan.foo}"/>

Resources