I need to invoke a method of backing component(#facescomponent) of composite component. I see others do this in articles but none of them has ever worked for me.
this how I invoke:
<ui:component xmlns="http://www.w3.org/1999/xhtml"
xmlns:f="http://java.sun.com/jsf/core"
xmlns:h="http://java.sun.com/jsf/html"
xmlns:ui="http://java.sun.com/jsf/facelets"
xmlns:cc="http://java.sun.com/jsf/composite">
<cc:interface componentType="formField"/>
<cc:implementation>
<h:commandButton value="doIt" action="#{cc.myAction}" ></h:commandButton>
</cc:implementation>
</ui:component>
and this is the backing component.
#FacesComponent("formField")
public class Field extends UICommand implements NamingContainer {
public Field() {
}
#Override
public String getFamily() {
return UINamingContainer.COMPONENT_FAMILY;
}
public String myAction() {
System.out.println("in action");//not printed
return null;
}
}
Shouldn't myAction method be invoked? What did I do wrong?
you do an invoke for property, for method need to use:
action="#{cc.myAction()}"
Related
This question already has an answer here:
Extended #FacesComponent as composite interface componentType renders nothing
(1 answer)
Closed 7 years ago.
I'm trying to build in a composite component in JSF with PrimeFaces.
in src/main/webapp/resources/components I have a component called editableLabel.xhtml
<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN"
"http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd">
<html xmlns="http://www.w3.org/1999/xhtml"
xmlns:composite="http://java.sun.com/jsf/composite"
xmlns:h="http://java.sun.com/jsf/html"
xmlns:p="http://primefaces.org/ui">
<h:head></h:head>
<h:body>
<composite:interface componentType="editableLabel">
<composite:attribute name="value" required="true"/>
<composite:attribute name="editMode" required="false" default="#{false}" type="java.lang.Boolean"/>
</composite:interface>
<composite:implementation>
<h:panelGroup id="editableLabelComponent">
<h:panelGroup rendered="#{cc.attrs.editMode}">
<p:inputText value="#{cc.attrs.value}"/>
<p:commandButton value="Update" actionListener="#{cc.update}"/>
<p:commandButton value="Cancel" actionListener="#{cc.cancel}"/>
</h:panelGroup>
<p:outputLabel id="display" value="#{cc.attrs.value}" rendered="#{!cc.attrs.editMode}">
<p:ajax event="click" listener="#{cc.toggleEditMode}" update="editableLabelComponent"/>
</p:outputLabel>
</h:panelGroup>
</composite:implementation>
</h:body>
</html>
Backed by a FacesComponent called EditableLabel.java
import javax.el.ValueExpression;
import javax.faces.component.FacesComponent;
import javax.faces.component.UIComponentBase;
import javax.faces.context.FacesContext;
import java.io.Serializable;
/**
* Created by labraham on 1/14/16.
*/
#FacesComponent(value = "editableLabel")
public class EditableLabel extends UIComponentBase implements Serializable {
private static final long serialVersionUID = 108467781935083432L;
private String oldValue = "";
/**
* Constructor
*/
public EditableLabel() {
super();
}
#Override
public String getFamily() {
return "foo.bar.components";
}
/**
*
*/
public void update() {
toggleEditMode();
FacesContext context = FacesContext.getCurrentInstance();
this.oldValue = (String) getValueExpression("value").getValue(context.getELContext());
}
/**
*
*/
public void cancel() {
toggleEditMode();
FacesContext context = FacesContext.getCurrentInstance();
ValueExpression valueExpression = getValueExpression("value");
valueExpression.setValue(context.getELContext(), this.oldValue);
}
/**
*
*/
public void toggleEditMode() {
FacesContext context = FacesContext.getCurrentInstance();
Boolean editModeValue = (Boolean) getValueExpression("editMode").getValue(context.getELContext());
ValueExpression editModeVe = getValueExpression("editMode");
editModeVe.setValue(context.getELContext(), String.valueOf(!editModeValue));
}
}
Yet when I try to stick it in an another file like so
foo.xhtml
<html xmlns="http://www.w3.org/1999/xhtml"
xmlns:h="http://xmlns.jcp.org/jsf/html"
xmlns:ui="http://xmlns.jcp.org/jsf/facelets"
xmlns:f="http://xmlns.jcp.org/jsf/core"
xmlns:p="http://primefaces.org/ui" xmlns:c="http://java.sun.com/jsp/jstl/core"
xmlns:comp="http://java.sun.com/jsf/composite/components"
>
...
<h3>Test</h3>
<comp:editableLabel value="#{foobean.testValue}"/>
It doesn't render. It tried removing the rendered attributes from the component (as well as editmode composite:attribute) and I've verified that it's looking for editableLabel.xhtml in the right place. foobean.testValue is just a string with a default value of "test value" and the appropriate getter and setter.
Why might PrimeFaces refuse to render this composite component?
Edit: I've also tried replacing the primefaces components in the composite component with their JSF equivalents and that didn't work. And I tried removing the ajax calls to see if maybe it was some issue with that. It wasn't.
Edit 2: Its an issue the my FacesComponent but I don't know what. Removing the component type attribute got it to render at least.
So I figured it out thanks to BalusC's answer to Extended #FacesComponent as composite interface componentType renders nothing
I needed to implement NamingContainer and getFamily() in EditableLabel.java
I've the below portlet view.xhtml:
<?xml version="1.0"?>
<f:view xmlns="http://www.w3.org/1999/xhtml"
xmlns:c="http://java.sun.com/jsp/jstl/core"
xmlns:f="http://java.sun.com/jsf/core"
xmlns:h="http://java.sun.com/jsf/html"
xmlns:ui="http://java.sun.com/jsf/facelets"
xmlns:p="http://primefaces.org/ui">
<h:body>
<h:form>
<h:commandButton value="TESTButton" action="#{navigationViewBean.submit}" />
<h:outputText value="TESTGetter: #{navigationViewBean.testField}" />
</h:form>
</h:body>
</f:view>
And this managed bean:
import javax.faces.bean.ManagedBean;
import javax.faces.bean.RequestScoped;
#ManagedBean(name = "navigationViewBean")
#RequestScoped
public class NavigationViewBean {
private String testField;
public boolean lol = false;
public void submit() {
System.out.print("TEST BUTTON INVOKED");
}
public String getTestField() {
System.out.print("TEST GETTER INVOKEDx");
return testField;
}
public void setTestField(String testField) {
this.testField = testField;
}
}
The only thing I try to do, is to call a method which prints something to my console. The problem is that no matter what I do, the action method is never invoked. The getter method is properly called.
What am I doing wrong?
Im not sure why, but after adding this line to my liferay-portlet.xml it fixed it.
<requires-namespaced-parameters>false</requires-namespaced-parameters>
And here the whole block:
<portlet>
<portlet-name>Test1</portlet-name>
<icon>/icon.png</icon>
<requires-namespaced-parameters>false</requires-namespaced-parameters>
<header-portlet-css>/css/main.css</header-portlet-css>
</portlet>
Can I use abstract class as CDI managed bean in JSF view? I want set or override attribute in derived class and use it in JSF page of parent abstract class. Derived view to set context which template parent view must show as common part all childs .
I heard that i can use abstract class with #Named annotation in JSF view, but i get error
Target Unreachable, identifier 'viewModel' resolved to null
If I change the abstract class to a typical class then its work. May be using abstract class in JSF view impossible?
ViewModel.java
#Named
#ConversationScoped
#Inherited
#Documented
#Stereotype
#Target({ TYPE })
#Retention(RUNTIME)
public abstract class ViewModel {
private String foo;
public void setFoo(String foo) {
this.foo = foo;
}
public String getFoo() {
return foo;
}
abstract void bar();
}
DerivedViewModel.java
#Named
#ConversationScoped
#Inherited
#Documented
#Stereotype
#Target({ TYPE })
#Retention(RUNTIME)
public class DerivedViewModel extends ViewModel {
public void init() {
this.setFoo("Foo");
}
#Override
void bar() {;}
}
View.xhtml
<ui:composition xmlns="http://www.w3.org/1999/xhtml"
xmlns:h="http://xmlns.jcp.org/jsf/html" xmlns:f="http://xmlns.jcp.org/jsf/core"
xmlns:ui="http://xmlns.jcp.org/jsf/facelets" xmlns:c="http://xmlns.jcp.org/jsp/jstl/core"
xmlns:fn="http://xmlns.jcp.org/jsp/jstl/functions" xmlns:pt="http://xmlns.jcp.org/jsf/passthrough"
xmlns:p="http://primefaces.org/ui" xmlns:pe="http://primefaces.org/ui/extensions"
xmlns:sys="http://argustelecom.ru/system" xmlns:o="http://omnifaces.org/ui">
<ui:param name="viewModel" value="#{viewModel}" />
<ui:define name="body">
<h:outputText value="#{viewModel.foo}" />
<ui:insert name="derived" />
</ui:define>
</ui:composition>
DerivedView.xhtml
<ui:composition template="View.xhtml" xmlns="http://www.w3.org/1999/xhtml"
xmlns:h="http://xmlns.jcp.org/jsf/html" xmlns:f="http://xmlns.jcp.org/jsf/core"
xmlns:ui="http://xmlns.jcp.org/jsf/facelets" xmlns:c="http://xmlns.jcp.org/jsp/jstl/core"
xmlns:fn="http://xmlns.jcp.org/jsp/jstl/functions" xmlns:pt="http://xmlns.jcp.org/jsf/passthrough"
xmlns:p="http://primefaces.org/ui" xmlns:pe="http://primefaces.org/ui/extensions"
xmlns:sys="http://argustelecom.ru/system" xmlns:o="http://omnifaces.org/ui">
<ui:param name="viewModel" value="#{derivedViewModel}" />
<ui:define name="metadata">
<f:metadata>
<f:viewAction action="#{derivedViewModel.init()}"/>
</f:metadata>
</ui:define>
<ui:define name="derived">
blablabla
</ui:define>
</ui:composition>
Forget EL or JSF. Think in terms of OO . Can you do this call.
viewModel.foo
Answer is no because it is abstract and viewModel can not exist as an instance of the abstract class ViewModel. For the exact same reason you can not use it in EL.
I'm trying to convert GET request parameters passed from another view like this:
<f:metadata>
<f:viewParam name="id"
value="#{targetViewBean.fooFromSourceView}"
converter="fooConverter"
converterMessage="Foo converter message"
required="true" requiredMessage="Foo required message"/>
<f:viewAction action="#{targetViewBean.doSomethingWithFoo()}"/>
</f:metadata>
But only the Converter.getAsString(..., Object value) method is called and value is always null, even thou the GET parameter is really sent.
I found BalusC blog post about this and, AFAIK, I followed it to the letter. Still no good. Here's the full code:
Source view
<h:head>
<title>Source view</title>
</h:head>
<h:body>
<ul>
<ui:repeat value="#{sourceViewBean.foos}" var="foo">
<li>
<h:link value="Foo \##{foo.id}" outcome="target-view">
<f:param name="id" value="#{foo.id}" />
</h:link>
</li>
</ui:repeat>
</ul>
</h:body>
Backing bean
#Named #ViewScoped
public class SourceViewBean implements Serializable {
public Collection<Foo> getFoos() {
return Db.INSTANCE.getFoos();
}
private static final long serialVersionUID = 1L;
}
Target view
<f:metadata>
<f:viewParam name="id"
value="#{targetViewBean.fooFromSourceView}"
converter="fooConverter"
converterMessage="Foo converter message"
required="true" requiredMessage="Foo required message"/>
<f:viewAction action="#{targetViewBean.doSomethingWithFoo()}"/>
</f:metadata>
<h:head>
<title>Target view</title>
</h:head>
<h:body>
<h:outputText value="ID: #{targetViewBean.fooFromSourceView.id}" />
</h:body>
Target view backing bean
#Named
#ViewScoped
public class TargetViewBean implements Serializable {
private Foo fooFromSourceView;
public void doSomethingWithFoo() {
System.out.println("Foo is here? " + fooFromSourceView != null);
}
public Foo getFooFromSourceView() {
return fooFromSourceView;
}
public void setFooFromSourceView(Foo fooFromSourceView) {
this.fooFromSourceView = fooFromSourceView;
}
private static final long serialVersionUID = 1L;
}
The converter
#FacesConverter(value = "fooConverter")
public class FooConverter implements Converter {
#Override
public Object getAsObject(
FacesContext context, UIComponent component, String value) {
if (value == null || !value.matches("\\d+")) {
return null;
}
for (Foo foo : Db.INSTANCE.getFoos()) {
if (foo.getId().equals(Integer.parseInt(value))) {
return foo;
}
}
throw new ConverterException(new FacesMessage("No Foo found!"));
}
#Override
public String getAsString(
FacesContext context, UIComponent component, Object value) {
if (!(value instanceof Foo) || ((Foo) value).getId() == null) {
return null;
}
return ((Foo) value).getId().toString();
}
}
I was able to find the problem after taking a look at the actual code you sent. The issue is not with the converter. It's with the xml namespaces at the top of your project. For instance, in source-view.xml you have
xmlns:h="http://xmlns.jcp.org/jsf/html"
xmlns:ui="http://xmlns.jcp.org/jsf/facelets"
xmlns:f="http://xmlns.jcp.org/jsf/core"
But they should be
xmlns:h="http://java.sun.com/jsf/html"
xmlns:ui="http://java.sun.com/jsf/facelets"
xmlns:f="http://java.sun.com/jsf/core">
And target-view.xhtml should be
xmlns:h="http://java.sun.com/jsf/html"
xmlns:f="http://java.sun.com/jsf/core">
GlassFish seems to change the namespaces for some reason. I didn't try to find out why it behaves like that though so keep that in mind. Anyway, once I changed it, the correct phases were being outputted in GlassFish's output window. So go and make the necessary change where needed.
Note: In case you are wondering why you are getting the following error
The metadata component needs to be nested within a f:metadata tag. Suggestion: enclose the necessary components within <f:metadata>
This seems to be a reported issue with JSF 2.2
Also, I'm not sure why your h:link is nested inside an h:form. It's not needed.
UPDATE
Seems like some of the taglibs are not fully functional or am I reading this wrong ?
https://java.net/jira/browse/JAVASERVERFACES-2868
I am finding view params will not be passed from a page where the backing bean is different on the target page. How can I pass the product param from test1.xhtml to test2.xhtml?
test.xhtml
<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd">
<html xmlns="http://www.w3.org/1999/xhtml"
xmlns:f="http://java.sun.com/jsf/core"
xmlns:h="http://java.sun.com/jsf/html"
xmlns:ui="http://java.sun.com/jsf/facelets"
xmlns:p="http://primefaces.org/ui" xmlns:o="http://omnifaces.org/ui">
<body>
<f:metadata>
<o:viewParam name="product" value="#{holder.value}"
converter="#{productConverter}"
converterMessage="Bad request. Unknown product." required="true"
requiredMessage="Bad request. Please use a link from within the system." />
</f:metadata>
<h:link outcome="/test2.xhtml" includeViewParams="true">link</h:link>
</body>
</html>
test2.xhtml
<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd">
<html xmlns="http://www.w3.org/1999/xhtml"
xmlns:f="http://java.sun.com/jsf/core"
xmlns:h="http://java.sun.com/jsf/html"
xmlns:ui="http://java.sun.com/jsf/facelets"
xmlns:p="http://primefaces.org/ui" xmlns:o="http://omnifaces.org/ui">
<h:head></h:head>
<body>
<f:metadata>
<o:viewParam name="product" value="#{holder2.value}"
converter="#{productConverter}"
converterMessage="Bad request. Unknown product." required="true"
requiredMessage="Bad request. Please use a link from within the system." />
</f:metadata>
<h:link outcome="/test.xhtml" includeViewParams="true">link</h:link>
</body>
</html>
Holder.java
#ManagedBean
#ViewScoped
public class Holder<T> implements Serializable {
private T value;
public T getValue() {
return value;
}
public void setValue(T value) {
this.value = value;
}
}
Holder2.java
#ManagedBean
#ViewScoped
public class Holder2<T> implements Serializable {
private T value;
public T getValue() {
return value;
}
public void setValue(T value) {
this.value = value;
}
}
Product.java
public class Product {
private String name;
public Product(String name) {
super();
this.name = name;
}
public String getName() {
return name;
}
}
Product Converter
public class ProductConverter implements Converter {
private Map<String,Product> productMap=new HashMap<String, Product>();
public ProductConverter(List<Product> products) {
for (Product product:products){
productMap.put(product.getName().toLowerCase(), product);
}
}
#Override
public Object getAsObject(FacesContext context, UIComponent component, String value) {
return productMap.get(value.toLowerCase());
}
#Override
public String getAsString(FacesContext context, UIComponent component, Object value) {
if (!(value instanceof Product) ) {
return null;
}
return ((Product) value).getName().toLowerCase();
}
}
<h:link outcome="/test2.xhtml?includeViewParams=true">link</h:link>
This is not the right way to let JSF include view parameters in a <h:link>. Supplying it as a query string parameter is only valid in action attribute of UICommand components.
You need the includeViewParams attribute of the <h:link> instead.
<h:link outcome="/test2.xhtml" includeViewParams="true">link</h:link>
#ViewScoped is only valid for postbacks - if you change the URL, the bean dies.
To pass parameters between facelets, use <ui:param>