I tried the following:
Something like the facelet I used:
...
<h:button value="x" outcome="nextpage">
<f:param name="#{myBean.PARAM_NAME}" value="someValue"/>
</h:button>
...
Something like the managed bean I used as a controller for the previous facelet:
#Named(value="myBean")
#ViewScoped
public MyBean implements Serializable
{
private static final String PARAM_NAME = "paramName";
public String getPARAM_NAME()
{ return PARAM_NAME };
#PostConstruct
public void init()
{
String passedParamValue = (String) FacesContext.getCurrentInstance().getExternalContext().getRequestParameterMap().get(
PARAM_NAME );
...
}
}
The advantage of this is : I use the param name in two places. In the facelet and in the managed bean as well. This two places are separated. I sould use constants to reduced the possibility of the mistyping. But it seems the name of the f:param does not evaluate EL expressions. (passedParamValue is always null). But if I directly wire the text 'paramName' to the name attribute, it works fine. Am I right or is there any way to use constants here?
Related
I would like to pass an value to a managed bean under the hood. So I have this managed bean:
#ManagedBean(name = "mbWorkOrderController")
#SessionScoped
public class WorkOrderController {
// more attributes...
private WorkOrder workOrderCurrent;
// more code here...
public WorkOrder getWorkOrderCurrent() {
return workOrderCurrent;
}
public void setWorkOrderCurrent(WorkOrder workOrderCurrent) {
this.workOrderCurrent = workOrderCurrent;
}
}
It holds a parameter workOrderCurrent of the custom type WorkOrder. The class WorkOrder has an attribute applicant of type String.
At the moment I am using a placeholder inside my inputtext to show the user, what he needs to type inside an inputText.
<p:inputText id="applicant"
value="#{mbWorkOrderController.workOrderCurrent.applicant}"
required="true" maxlength="6"
placeholder="#{mbUserController.userLoggedIn.username}" />
What I want to do, is to automatically pass the value of mbUserController.userLoggedIn.username to mbWorkOrderController.workOrderCurrent.applicant and remove the inputText for applicant completely from my form.
I tried to use c:set:
<c:set value="#{mbUserController.userLoggedIn.username}" target="#{mbWorkOrderController}" property="workOrderCurrent.applicant" />
But unfortunatelly I get a javax.servlet.ServletException with the message:
The class 'WorkOrderController' does not have the property 'workOrderCurrent.applicant'.
Does anybody have an advice?
The class 'WorkOrderController' does not have the property 'workOrderCurrent.applicant'.
Your <c:set> syntax is incorrect.
<c:set value="#{mbUserController.userLoggedIn.username}"
target="#{mbWorkOrderController}"
property="workOrderCurrent.applicant" />
You seem to be thinking that the part..
value="#{mbWorkOrderController.workOrderCurrent.applicant}"
..works under the covers as below:
WorkOrderCurrent workOrderCurrent = mbWorkOrderController.getWorkOrderCurrent();
workOrderCurrent.setApplicant(applicant);
mbWorkOrderController.setWorkOrderCurrent(workOrderCurrent);
This isn't true. It works under the covers as below:
mbWorkOrderController.getWorkOrderCurrent().setApplicant(applicant);
The correct <c:set> syntax is therefore as below:
<c:set value="#{mbUserController.userLoggedIn.username}"
target="#{mbWorkOrderController.workOrderCurrent}"
property="applicant" />
That said, all of this isn't the correct solution to the concrete problem you actually tried to solve. You should perform model prepopulating in the model itself. This can be achieved by using #ManagedProperty to reference another bean property and by using #PostConstruct to perform initialization based on it.
#ManagedBean(name = "mbWorkOrderController")
#SessionScoped
public class WorkOrderController {
#ManagedProperty("#{mbUserController.userLoggedIn}")
private User userLoggedIn;
#PostConstruct
public void init() {
workOrderCurrent.setApplicant(userLoggedIn.getUsername());
}
// ...
}
Perhaps you could explain the context a bit more, but here's another solution. If you're navigating from another page, you can pass some identifier of work WorkOrder in the URL, like this http://host:port/context/page.xhtml?workOrderId=1.
Then, you can set the identifier in the managed bean like this:
<h:html>
<f:viewParam name="workOrderId" value="#{mbWorkOrderController.id}"/>
</h:html>
You'll have to add a new property to your bean:
public class WorkOrderController {
private long id;
public long getId() { return id; }
public void setId(long id) { this.id = id; }
// ...
}
And then, after the property has been set by JSF, you can find the work order in a lifecycle event:
<h:html>
<f:viewParam name="workOrderId" value="#{mbWorkOrderController.id}"/>
<f:event type="preRenderView" listener="#{mbWorkOrderController.findWorkOrder()}"/>
</h:html>
public class WorkOrderController {
private long id;
public long getId() { return id; }
public void setId(long id) { this.id = id; }
public void findWorkOrder() {
this.workOrderCurrent = null /* some way of finding the work order */
}
// ...
}
This strategy has the advantage of letting you have bookmarkable URLs.
i have a submit button. This submit button has an "action" attribute. But this action attribute should always call another function (some kind of generic). So i want to call a function dynamically. This is because i need to reuse this component. I just don't know which Type the action attribute needs (Method, String, etc. ?) and how to refer correctly to the wanted "BeanWithMethodToCall".
#Named
#SessionScoped
public class BeanWithMethodToCall{
#Inject
private BeanWhichIsCalledFromEL elBean;
public void methodToCall(){
//do something
}
public void someLogic(){
// here the wanted method is set on the bean which is later on called from el
elBean.setMethodToCall("methodToCall");
}
}
#Named
#SessionScoped
public class BeanWhichIsCalledFromEL{
// i don't know the correct type of this :S
private String method;
public void setMethodToCall(String method){
this.method = method;
}
// i don't know the correct return type of this :S
public String getMethodToExecute(){
//this method is called in the action attribute in the xhtml
// and should return a dynamic function to call
}
}
In EL:
<h:commandButton value="Cancel" action="#{beanWhichIsCalledFromEL.getMethodToExecute()}">
<f:ajax render="#form"/>
</h:commandButton>
This seems tricky.. I hope somebody can help me. Do i need Reflection ? or an EL Resolver or anything else ??
Use the brace notation #{bean[foo]} to evaluate "dynamic" method and property names.
Your specific case can be solved as below:
<h:commandButton ... action="#{bean[bean.methodToExecute]}">
See also:
Dynamic ui include and commandButton
I have different objects which all implements the same interfaces. All of these objects need to be selectable by <p:selectCheckboxMenu/>. Default values for those objects and selected values are placed in same Map<?,?>, and few such Maps grouped together inside another Map. It sounds complicated but please look at the code below and all will be clear.
When I select an object, converter get a list of all objects from MyBean (CDI bean), looking by uuid required object and return it, without throwing any exception. The problem begins when I try to work with selected objects. For example this line of code inside:
onObjectChange() method from MyBean:
List<AllObjects> objects= objectContainer.getControllers().get("Object 1").get("selected");
throws an exception:
java.lang.ClassCastException: [Ljava.lang.Object; incompatible with java.util.List
And indeed when I hover mouse over objectContainer I see that it contains object of type selected=[Ljava.lang.Object;#dba1b6e7} But when I evaluate same line of code inside Expressions panel of Eclipse I get the required values: MyObject1#d8f0f5f8
I don't understand in general is it possible to do what am I doing, i.e. few different objects with same interface to be selectable by <p:selectCheckboxMenu/>. And if yes, why do I have this casting problem? My colleague said that it might be a problem with my converter and I tend to agree with she, but don't know is it correct and if yes, how to solve it.
UPDATE: It looks that problem not inside Converter but due to fact that I pass Collection to collect selected values dynamically, as a value of <ui:param/>. I pass it as List<AllObjects> and get it back as Object. I can cast it then to Object[] and every object inside it to appropriated object by using introspection and it works. But why it mutates initial object? It shouldn't do this.
Thank you in advance and my code below:
This is an interface:
public interfaces AllObjects{
public String getName();
}
There are multiple objects, MyObject, MyObject1, MyObject2 which implement interfaces above:
public MyObject implements AllObjects{
...
}
This is my bean and how my objects are initialized:
public MyBean {
Map<String, Map<String,List<AllObjects>>> objectContainer = new LinkedHashMap<String, Map<String,List<AllObjects>>>();
public void init(){
Map<String,List<AllObjects>> nameValuesPairs1 = new LinkedHashMap<String,List<AllObjects>>();
List<AllObjects> allSelectedObjects1 = new ArrayList<AllObjects>();
List<AllObjects> allDefaultObjects1 = new ArrayList<AllObjects>();
nameValuesPairs.put("default",allDefaultObjects1);
nameValuesPairs.put("selected",allSelectedObjects1);
Map<String,List<AllObjects>> nameValuesPairs2 = new LinkedHashMap<String,List<AllObjects>>();
List<AllObjects> allSelectedObjects2 = new ArrayList<AllObjects>();
List<AllObjects> allDefaultObjects2 = new ArrayList<AllObjects>();
nameValuesPairs.put("default",allDefaultObjects2);
nameValuesPairs.put("selected",allSelectedObjects2);
objectContainer.put("Object 1", nameValuesPairs1);
objectContainer.put("Object 2", nameValuesPairs2);
}
public void onObjectChange(){
...
List<AllObjects> objects= objectContainer .getControllers().get("Object 1").get("selected"); //throws exception
...
}
}
My *.xhtml page:
<h:panelGroup id="object_panel">
<ui:repeat id="objects_id" var="object" value="#{myBean.objectContainer.entrySet().toArray()}">
<p:selectCheckboxMenu
value="#{object.value['selected']}" label="#{object.key}"
converter="#{myObjectConverter}"
filter="true"
filterMatchMode="startsWith"
panelStyle="width:250px">
<f:selectItems value="#{object.value['default']}" var="value" itemValue="#{value}" itemLabel="#{value.name}" />
<p:ajax event="change" process="#this #parent" listener="#{myBean.onObjectChange}"/>
</p:selectCheckboxMenu>
</ui:repeat>
</h:panelGroup>
And converter:
public class ChartParameterConverter implements Converter, Serializable {
#Inject
private MyBean myBean;
#Override
public Object getAsObject(FacesContext context, UIComponent component, String value) throws ConverterException {
AllObjects result = null;
...
//here to result assigned MyObject1 or MyObject2 type depends on condition and it being returned
...
return result;
}
...
}
Ok, it looks that <ui:repeat> and <p:selectCheckboxMenu> not work well with DataModel which I used, Map<String,Map<String,List<MyObject>>>. I've changed my DataModel in the following way:
public ObjectContainer{
private String name;
private List<MyObject> defaultObjects;
private List<MyObject> selectedObbjects;
}
and pass to <ui:param> it as List<ObjectContainer>. so my *.xhtml page looks in the following way:
<p:selectCheckboxMenu
value="#{object.selectedObjects}" label="#{object.name}"
converter="#{myObjectConverter}"
filter="true"
filterMatchMode="startsWith"
panelStyle="width:250px">
<f:selectItems value="#{object.defaultObjects}" var="value" itemValue="#{value}" itemLabel="#{value.name}" />
<p:ajax event="change" process="#this #parent" listener="#{myBean.onObjectChange}"/>
</p:selectCheckboxMenu>
</ui:repeat>
And now everything works as it should.
And I throwed away my custom converter and use SelectItemsConverter from Omnifaces's library. Highly recommended change, code become much simpler and readable.
You could do a unique Tuple for each Object, The Tuple must be converted to unique String.. And you could have the posible values in a Array..
static Map<String,Object> uniques = new LinkedHashMap<>();
static{
//you could save the possible values in a Singleton Bean
uniques.put(key,value)...
}
In your Converter
getAsString -> Return a Key from Value
getAsObject -> Return a Value by Key
I'm trying to use SelectItemsConverter with PrimeFaces Picklist.
XHTML:
<p:pickList id="plUpdateFirma" value="#{bsvttController.dlmFirma}" var="plFirma"
itemLabel="#{plFirma.schluesselFirma}" itemValue="#{plFirma}"
converter="FirmaConverter">
<f:facet name="sourceCaption">
Vorjahr
</f:facet>
<f:facet name="targetCaption">
#{bsvttController.selSaison}
</f:facet>
<p:column>
#{plFirma.schluesselFirma}
</p:column>
</p:pickList>
Converter:
#FacesConverter(value = "FirmaConverter")
public class FirmaConverter extends SelectItemsConverter
{
#Override
public String getAsString(final FacesContext facesContext, final UIComponent component, final Object object)
{
return ((Firma) object).getSchluesselFirma();
}
}
Bean:
#ManagedBean
#ViewScoped
public class BsvttController implements Serializable
{
private DualListModel<Firma> dlmFirma;
private List<Firma> dlmFirmaSource;
private List<Firma> dlmFirmaTarget;
private Firma firma;
#PostConstruct
public void init()
{
dlmFirmaSource = FirmaPersistenz.leseFirmaAlle();
dlmFirmaTarget = new ArrayList<Firma>();
dlmFirma = new DualListModel<>(dlmFirmaSource, dlmFirmaTarget);
}
public DualListModel<Firma> getDlmFirma()
{
return dlmFirma;
}
public List<Firma> getDlmFirmaSource()
{
return dlmFirmaSource;
}
public List<Firma> getDlmFirmaTarget()
{
return dlmFirmaTarget;
}
public void setDlmFirma(DualListModel<Firma> dlmFirma)
{
this.dlmFirma = dlmFirma;
}
public void setDlmFirmaSource(List<Firma> dlmFirmaSource)
{
this.dlmFirmaSource = dlmFirmaSource;
}
public void setDlmFirmaTarget(List<Firma> dlmFirmaTarget)
{
this.dlmFirmaTarget = dlmFirmaTarget;
}
}
While debugging converter I could see that getAsString method is working fine. But after submitting the form both arraylists (dlmFirmaSource and dlmFirmaTarget) are empty.
OmniFaces showcase says that
"The omnifaces.SelectItemsConverter allows you to populate e.g. a drop-down with complex Java model objects as value of f:selectItems and have JSF convert those automatically back without the need to provide a custom converter which may need to do the job based on possibly expensive service/DAO operations."
But in case of PickList component there doesn't exist any f:selectItems tag.
Does SelectItemsConverter even support PickList component?
Does SelectItemsConverter even support PickList component?
No, it doesn't.
Since OmniFaces 1.5, you can use omnifaces.ListConverter or omnifaces.ListIndexConverter for the desired purpose. See also the ListConverter showcase example which also demonstrates the usage on <p:pickList>.
No, the SelectItemsConverter handles conversion of core JSF SelectItem objects for use with various JSF components.
The class DualListModel is a PrimeFaces specific class meant for use with advanced PrimeFaces data components. The workaround of course is to possible use a #PostConstruct method to initialize your DualListModel in the managed bean so that it does not require a converter, or you can simply implement the converter in the traditional way. From the PrimeFaces guide on the converter attribute of Pick List:
An el expression or a literal text that defines a
converter for the component. When it’s an EL
expression, it’s resolved to a converter instance.
In case it’s a static text, it must refer to a
converter id
What is the difference between using value and binding with JavaServer Faces, and when would you use one as opposed to the other? To make it clearer what my question is, a couple of simple examples are given here.
Normally with JSF in the XHTML code you would use "value" as here:
<h:form>
<h:inputText value="#{hello.inputText}"/>
<h:commandButton value="Click Me!" action="#{hello.action}"/>
<h:outputText value="#{hello.outputText}"/>
</h:form>
Then the bean is:
// Imports
#ManagedBean(name="hello")
#RequestScoped
public class Hello implements Serializable {
private String inputText;
private String outputText;
public void setInputText(String inputText) {
this.inputText = inputText;
}
public String getInputText() {
return inputText;
}
// Other getters and setters etc.
// Other methods etc.
public String action() {
// Do other things
return "success";
}
}
However, when using "binding", the XHTML code is:
<h:form>
<h:inputText binding="#{backing_hello.inputText}"/>
<h:commandButton value="Click Me!" action="#{backing_hello.action}"/>
<h:outputText value="Hello!" binding="#{backing_hello.outputText}"/>
</h:form>
and the correspondibg bean is called a backing bean, and is here:
// Imports
#ManagedBean(name="backing_hello")
#RequestScoped
public class Hello implements Serializable {
private HtmlInputText inputText;
private HtmlOutputText outputText;
public void setInputText(HtmlInputText inputText) {
this.inputText = inputText;
}
public HtmlInputText getInputText() {
return inputText;
}
// Other getters and setters etc.
// Other methods etc.
public String action() {
// Do other things
return "success";
}
}
What practical differences are there between the two systems, and when would you use a backing bean rather than a regular bean? Is it possible to use both?
I have been confused about this for some time, and would most appreciate having this cleared up.
value attribute represents the value of the component. It is the text that you see inside your text box when you open the page in browser.
binding attribute is used to bind your component to a bean property. For an example in your code your inputText component is bound to the bean like this.
#{backing_hello.inputText}`
It means that you can access the whole component and all its properties in your code as a UIComponent object. You can do lot of works with the component because now it is available in your java code.
For an example you can change its style like this.
public HtmlInputText getInputText() {
inputText.setStyle("color:red");
return inputText;
}
Or simply to disable the component according to a bean property
if(someBoolean) {
inputText.setDisabled(true);
}
and so on....
Sometimes we don't really need to apply the value of UIComponent to a bean property. For example you might need to access the UIComponent and work with it without applying its value to the model property. In such cases it's good to use a backing bean rather than a regular bean. On the other hand in some situations we might need to work with the values of the UIComponent without any need of programmatic access to them. In this case you can just go with the regular beans.
So, the rule is that use a backing bean only when you need programmatic access to the components declared in the view. In other cases use the regular beans.