I try to add action listener into my custom component.
I have custom datatable which wrapping tomahawk datatable.
I have custom dataScroller which wrapping tomahawk datascroller.
I need to pass into dataScroller method defined in datatable.
<custom:dataScroller actionListener="#{someBean['someMethod']}"...
or
<custom:dataScroller actionListener="#{someBean.someMethod}"...
In taglib file:
<tag>
<name>dataScroller</name>
<tag-class>java.lang.Object</tag-class>
<body-content>scriptless</body-content>
...
<attribute>
<name>actionListener</name>
<deferred-method>
<method-signature>
void myMethod(javax.faces.event.ActionEvent )
</method-signature>
</deferred-method>
</attribute>
...
</tag>
in dataScroller.xhtml
<t:dataScroller id="scroller_#{for}" for="#{for}"
fastStep="#{fastStep}"
paginatorRenderLinkForActive="false"
paginator="true"
paginatorMaxPages="10"
paginatorActiveColumnStyle="font-weight:bold;"
renderFacetsIfSinglePage="#{allwaysRender}"
binding="#{applicationBean.scroll}"
actionListener="#{actionListener}"// HERE is the actionListener
immediate="false">
this gaves me javax.faces.el.EvaluationException: ... Property 'someMethod' not found on type ...
It marks t he method as property but it should be marked as method
public void someMethod(ActionEvent sae) {
LOGGER.info("Event: #0" + sae.getClass().toString());
}
Where should be the problem?
Related
Following on from the response by the legendary BalusC to this post:
How to programmatically or dynamically create a composite component in JSF 2
Had I sufficient points I would attach a comment to that post -- but I don't have sufficient points .
Problem as follows.
I'm trying to set up a commandButton which adds a JSF composite component dynamically to an xhtml file. With the intention that clicking it multiple times will put multiple instances of the component on the page.
So I have a button on an XHTML file:
<h:commandButton action="#{assessingController.addQuestion}" value="Add a Question"></h:commandButton>
Which calls a method on AssessingController:
public void addQuestion() {
UIComponent parent = null;
includeCompositeComponent(parent, "http://xmlns.jcp.org/jsf/composite/components", "questionComposite", "someId");
}
UIComponent parent = null; -- because it has to be instantiated or referenced somehow, before being passed into includeCompositeComponent . But as noted below - making it null might be causing the null pointer exception, (so what should I do instead?)
includeCompositeComponent method is as per the JSF 2.2 method referred to by BalusC in the above post:
public void includeCompositeComponent(UIComponent parent, String taglibURI, String tagName, String id) {
FacesContext context = FacesContext.getCurrentInstance();
UIComponent composite = context.getApplication().getViewHandler()
.getViewDeclarationLanguage(context, context.getViewRoot().getViewId())
.createComponent(context, taglibURI, tagName, null);
composite.setId(id);
parent.getChildren().add(composite);
}
When I click on the commandButton, logs as follows:
javax.faces.el.EvaluationException: java.lang.NullPointerException
at javax.faces.component.MethodBindingMethodExpressionAdapter.invoke(MethodBindingMethodExpressionAdapter.java:101)
at com.sun.faces.application.ActionListenerImpl.processAction(ActionListenerImpl.java:102)
at javax.faces.component.UICommand.broadcast(UICommand.java:315) ...
Caused by: java.lang.NullPointerException
at controllers.AssessingController.includeCompositeComponent(AssessingController.java:123)
AssessingController.java:123 is this line:
parent.getChildren().add(composite);
Composite is not null (checked that).
So, obviously perhaps, - parent is null and that's where the problem is.
So how can I better reference UIComponent parent to begin with?
Do I need to make it refer to something on the xhtml file? I'm presuming it needs some kind of a placeholder which will serve as the parent(?). Right now all there is on the xhtml page is the commandButton.
Thank you all.
The parent is supposed to represent the component where you'd like to include the composite component in.
Imagine that you ultimately want to end up with this plain XHTML representation:
<h:panelGroup id="questions">
<your:questionComposite />
</h:panelGroup>
You should then supply exactly that <h:panelGroup> component as parent.
<h:form>
<h:commandButton ... action="#{bean.addQuestion}" />
</h:form>
<h:panelGroup id="questions" />
public void addQuestion() {
UIComponent parent = context.getViewRoot().findComponent("questions");
// ...
}
Or, by passing the concrete component itself:
<h:form>
<h:commandButton ... action="#{bean.addQuestion(questions)}" />
</h:form>
<h:panelGroup id="questions" binding="#{questions}" />
public void addQuestion(UIComponent parent) {
// ...
}
Unrelated to the concrete problem: there's a thinking/design mistake here. You should rather use an <ui:repeat><your:compositeComponent> and then feed from a #ViewScoped bean to the <ui:repeat> a dynamically sized list of entities representing the composite's model value.
<h:form>
<h:commandButton ... action="#{bean.addQuestion}" />
</h:form>
<ui:repeat value="#{bean.questions}" var="question">
<your:questionComposite value="#{question}" />
</ui:repeat>
private List<Question> questions;
public void addQuestion() {
questions.add(new Question());
}
Anytime you need to deal with raw UIComponent instances in a backing bean, take a pause and carefully research or ask if you're really doing things the right way. Perhaps it belongs in a backing component instead, or could just be done with pure XHTML.
See also:
How to dynamically add JSF components
How does the 'binding' attribute work in JSF? When and how should it be used?
Prerequisites:
Glasfish 3.1
JSF 2.1
Primefaces 5.2
User Story:
I want to implement a delete row function on my Primefaces DataTable, the Delete Function has to be displayed within the table.
Implementation:
datatable header
<p:dataTable value="#{a.list}" var="var">
delete
<p:column headerText="Delete">
<p:commandLink value="-" action="#{a.delete(var)}" />
</p:column>
delete method in bean
public void delete(Something sth) {
model.getList().remove(sth);
}
Outcome:
When hovering over the commandLink its showing me this Uniform Resource Locator localhost/applicationname/#
Eclipse is giving me the Facelet Validator Warning Marker Syntax Error on this ExpressionLanguage Code #{a.delete(var)}
Question:
What am i missing in order to delete the row?
Solution:
I have changed to commandlink from JSF (not primefaces) and got the Error, that my method shouldnt be void, but String after changing that and returning null it works...
public String delete(Something sth) {
model.getList().remove(sth); return null;
}
In order to get the row numbers of a datatable I got an answer here that I could bind the dataTable directly to the view (JSF 2 dataTable row index without dataModel).
I'm using that function in a composite component and there may be several of those in the same page. I believe that the binding makes it impossible to use more than one component on each page; is it possible to bind each table "separately" somehow?
Create a backing component class with an UIData property.
#FacesComponent("fooComponent")
public class FooComponent extends UINamingContainer {
private UIData table;
// +getter +setter
}
And bind it to #{cc.table} instead (the #{cc} refers the current backing component instance).
<cc:interface componentType="fooComponent">
...
</cc:interface>
<cc:implementation>
<h:dataTable binding="#{cc.table}" ...>
<h:column>#{cc.table.rowIndex + 1}</h:column>
...
</h:dataTable>
</cc:implementation>
Just use ui:repeat instead, it has built in support via varStatus.index.
JSF 1.2 DataTable
I know how to remove the row from datatable writing following code.
jsp
<h:graphicImage id="deleteRowBtn_img" url="../../images/table_icon_delete.gif" style="cursor:pointer" alt="Delete Row">
<a4j:support id="deleteRowBtn" event="onclick" actionListener="#{mnpAction.deleteMultiNoPortRow}" reRender="multiNoPortTable" oncomplete="resetViewConfigs();"/>
</h:graphicImage>
action bean
public void deleteMultiNoPortRow(ActionEvent ae) {
{
int index = abcBean.getDataTable().getRowIndex();
mnpBean.getMultiNoPortingList().remove(index);
}
}
But i want to know is there any other way to remove row from datatable in JSF1.2.
Any help regarding this appreciate!!!!!!
You can get the same appearance and functionality by using an a4j:commandButton and its image attribute instead of <h:graphicImage> as below.
<a4j:commandButton image="../../images/table_icon_delete.gif" actionListener="#{mnpAction.deleteMultiNoPortRow}"/>
If your <h:graphicImage> is in a column of the table, you can pass the var of the table to a method in your baking bean and remove that element from the list without having to use the row index. Here use action instead of actionListener.
<a4j:support id="deleteRowBtn" event="onclick" action="#{mnpAction.remove(myVar)}".../>
In mnpAction bean (Assuming the type of your list is T)
public void remove(T s) {
mnpBean.getMultiNoPortingList().remove(s);
}
Edit:
Since you are using JSF1.2 you may not use #{mnpAction.remove(myVar)}" to pass parameters to the bean if you don't like to upgrade your EL library.
I have two custom components:
CustomUIComponent extends UIComponentBase
CustomChildUIComponent extends UIComponentBase
In CustomUIComponent I implement encodeBegin, encodeChildren and encodeEnd - in encodeChildren I set some custom attribute to be forwarded to the child component.
In CustomChildUIComponent I implement only encodeBegin.
In addition to these classes I added the components in the faces-config.xml:
<component>
<component-type>test.JsfMessage</component-type>
<component-class>test.CustomUIComponent</component-class>
</component>
<component>
<component-type>test.JsfChildMessage</component-type>
<component-class>test.CustomChildUIComponent</component-class>
</component>
And I have the custom taglib.xml configured in the web.xml and contains:
<tag>
<tag-name>customMessage</tag-name>
<component>
<component-type>test.JsfMessage</component-type>
</component>
</tag>
<tag>
<tag-name>customChildMessage</tag-name>
<component>
<component-type>test.JsfChildMessage</component-type>
</component>
</tag>
Finally in my Facelets page I am trying to execute:
<myns:customMessage message="Hello World!!!" var="mytestvar">
<myns:customChildMessage partnermsg="#{mytestvar}" />
</myns:customMessage>
The result is that the parent is rendered but the child component does not.
Am I doing something wrong?
I tried checking the super.encodeChildren but it checks:
Renderer renderer = getRenderer(context);
if(renderer != null) ...
I am not using a renderer class, but as I understand it is not a must.
The encodeChildren() method of your custom component will only be called if the getRendersChildren() method of the very same custom component returns true. This is specified in the javadoc:
This method will only be called if the rendersChildren property is true.
So make sure that you've overridden that accordingly, it namely defaults to false:
#Override
public boolean getRendersChildren() {
return true;
}