I have a tiles definition like
<definition name="tasks" template="/jsp/layout/layout.jsp">
<put-attribute name="header" value="/jsp/layout/header.jsp"/>
<put-attribute name="nav" value="/jsp/layout/navigation.jsp"/>
<put-attribute name="menu" value="/jsp/task/menu.jsp#ShowUser" />
</definition>
I want to add a anchor in the value for an attribute and this anchor needs to be set based on the attribute set the controller.
For eg
<put-attribute name="menu" value="/jsp/task/menu.jsp#ShowUser" />
However this does not seem to work.
Any idea how this can be done?
One approach to this (there may be another way?) would be to combine the use of OGNL in your action result location and a wild card in your Tile definition.
Suppose I have this action:
public class DynamicTileAction {
MyModel model
public String execute() {
return "success";
}
public MyModel getModel() {
return this.model;
}
//other code...
}
And this result definition:
<result name="success" type="tiles">dynamic.tile.${model.someField}</result>
Then in the tiles.xml I can do this:
<definition name="dynamic.tile.*">
<put-attribute name="dynamicField" value="{1}" />
</definition>
or, you can use it to dynamically include a JSP:
<definition name="dynamic.tile.*">
<put-attribute name="content" value="/WEB-INF/content/dynamic/{1}.jsp" />
</definition>
Then, each place that you see {1} above will equal the value of getModel().getSomeField().
Related
I have a template that's part of a form to edit some element. The action to be performed is different depending on the page in which it is included. So I pass the action method as a parameter:
<ui:param name="option" value="#{someOptionBean}" />
...
<ui:include src="/WEB-INF/jsf/value-edit.xhtml">
<ui:param name="controllerParam" value="#{optionController}" />
<ui:param name="elementParam" value="#{option}" />
<ui:param name="actionParam" value="updateOption" />
</ui:include>
or:
<ui:param name="property" value="#{somePropertyBean}" />
...
<ui:include src="/WEB-INF/jsf/value-edit.xhtml">
<ui:param name="controllerParam" value="#{propertyController}" />
<ui:param name="elementParam" value="#{property}" />
<ui:param name="actionParam" value="updateProperty" />
</ui:include>
and in value-edit.xhtml there is a command button:
<p:commandButton value="Update" action="#{controllerParam[actionParam](elementParam)}" />
So far everything works fine.
My problem is that now the action methods don't have the same number of parameters. They are:
public void updateOption(Option option) { ... }
public void updateProperty(Item item, Prop property) { ... }
so I now want to be able to also define the action parameters to have something like:
<ui:param name="actionParam" value="updateOption(option)" />
<ui:param name="actionParam" value="updateProperty(item, property)" />
or something like:
<ui:param name="method" value="updateProperty" />
<ui:param name="parameters" value="item, property" />
I've read the docs (Value and Method Expressions / Parameterized Method Calls) and I'm not sure if this is possible.
Is there any way to achieve this?
Finally I solved this creating a MethodExpression in the controller
Now the ui:include looks like:
<ui:param name="option" value="#{someOptionBean}" />
...
<ui:include src="/WEB-INF/jsf/value-edit.xhtml">
<ui:param name="actionParam" value="#{optionController.getUpdateAction()}" />
</ui:include>
and
<ui:param name="item" value="#{someItemBean}" />
<ui:param name="property" value="#{somePropertyBean}" />
...
<ui:include src="/WEB-INF/jsf/value-edit.xhtml">
<ui:param name="actionParam" value="#{propertyController.getUpdateAction()}" />
</ui:include>
In value-edit.xhtml the command button is:
<p:commandButton value="Update" action="#{actionParam}" />
The getUpdateAction creates the MethodExpression with the corresponding parameters for each controller:
public class OptionController {
...
public void updateOption(Option option) { ... }
public MethodExpression getUpdateAction() {
return createMethodExpression("#{optionController.updateOption(option)}", String.class, Option.class);
}
...
}
public class PropertyController {
...
public void updateProperty(Item item, Prop property) { ... }
public MethodExpression getUpdateAction() {
return createMethodExpression("#{propertyController.updateProperty(item, property)}", String.class, Item.class, Prop.class);
}
...
}
where createMethodExpression is:
public static MethodExpression createMethodExpression(String expression, Class<?> expectedReturnType, Class<?>... expectedParameterTypes) {
FacesContext facesContext = FacesContext.getCurrentInstance();
return facesContext.getApplication().getExpressionFactory().createMethodExpression(
facesContext.getELContext(), expression, expectedReturnType, expectedParameterTypes);
}
I have a very simple JSF 2/Facelets page that looks like this:
<ui:repeat value="#{myBean.names}" var="_name">
<h:commandLink value="#{_name}" action="#{myBean.sayHello(_name)}">
<f:ajax execute="#this"/>
</h:commandLink>
<br/>
</ui:repeat>
The backing bean provides a java.util.List<String> with names and the action-method just prints a "hello <name>" message to standard output.
This works fine. I get a list of names in the browser and a click fires the action-method that says hello to the specified name.
The Problem arises, when I want to put this code in a composite component that does the iteration and renders the actual link via a facet:
<ui:component xmlns="http://www.w3.org/1999/xhtml"
xmlns:f="http://xmlns.jcp.org/jsf/core"
xmlns:ui="http://xmlns.jcp.org/jsf/facelets"
xmlns:cc="http://xmlns.jcp.org/jsf/composite">
<cc:interface>
<cc:attribute name="value" type="java.util.List" required="true" />
<cc:facet name="content" />
</cc:interface>
<cc:implementation>
<ui:repeat value="#{cc.attrs.value}" var="_name">
<cc:renderFacet name="content"/>
</ui:repeat>
</cc:implementation>
</ui:component>
I use the composite component like this:
<my:myComp value="#{bean.names}">
<f:facet name="content">
<h:commandLink value="#{_name}" action="#{bean.sayHello(_name)}">
<f:ajax execute="#this"/>
</h:commandLink>
<br/>
</f:facet>
</my:myComp>
In the browser I get a list of names that looks exactly like before. But clicking a link now renders a "hello null" message. So _name is resolved correctly in the value attribute of <h:commandLink> but not in the action attribute.
I also tried using actionListener instead of action or the listener attribute from the <f:ajax> tag with no difference.
Could anybody shade some light on this issue?
My environment:
WildFly 8.1 with
JSF 2.2.6 (Mojarra)
The issue has to do with the scope of the variable in this case _name which is evaluated once when the <ui:repeat/> is being processed. In my case, I ran your code and it produced Hello John even though their were other names in my list. To get around this, I introduced a <f:param/> that would contain the value of the _name, and modified your code as follows:
<h:form>
<my:myComp value="#{bean.names}">
<f:facet name="content">
<h:commandLink value="#{_name}" action="#{bean.sayHello()}">
<f:param name="name_" value="#{_name}"/>
<f:ajax execute="#this"/>
</h:commandLink>
<br/>
</f:facet>
</my:myComp>
</h:form>
I also modified the sayHello() method as follows for a #RequestScoped bean:
#ManagedProperty(value = "#{facesContext}")
private FacesContext facesContext;
public void setFacesContext(FacesContext facesContext) {
this.facesContext = facesContext;
}
public void sayHello() {
Map<String, String> params = facesContext.getExternalContext()
.getRequestParameterMap();
String name = params.get("name_");
System.out.println("Hello " + name);
}
You could change this to something shorter in a #ViewScoped bean to:
public void sayHello() {
Map<String, String> params = FacesContext.getCurrentInstance()
.getExternalContext().getRequestParameterMap();
String name = params.get("name_");
System.out.println("Hello " + name);
}
The final result is that it prints out the names correctly.
Im using displaytable with tiles. Problem is in my crud application, when I search something its loading data into display table,
and when I click on 2nd page its load data to 2nd page as I give requestURI="searchorgs". All works fine upto that,
Then I call Edit template and after submitting edited data it should load data to table. Its also work fine but when I click 2nd page
Its goes to search page as I mention in requestURI="searchorgs". I need to keep in same page with out moving to search page. Same table is insert in to add,edit,search jsp pages in tiles.xml. I dont want to define 3 separate tables for this.
Application I struts2 tiles integration one.
action class search method :
public String search() {
organisationSearch = new OrganisationSearch();
organisationSearch.setAoName(aoName);
orglist = orgBo.searchOrg(organisationSearch);
return "search";
}
Struts xml :
<action name="*orgs" class="com.ast.action.admin.OraganisationAction"
method="{1}">
<result name="add" type="tiles">orgAddTemplate</result>
<result name="search" type="tiles">orgTemplate</result>
<result name="delete" type="tiles">orgTemplate</result>
<result name="edit" type="tiles">orgEditTemplate</result>
<r
</action>
table :
<s:form theme="simple" id="delete" action="deleteorgs">
<display:table id="studentTable" name="orglist" pagesize="5" cellpadding="5px;" id="row" cellspacing="5px;"
style="margin-left:50px;margin-top:20px;" requestURI="searchorgs">
<display:column style="width:5px;">
<s:checkbox name="chkBox" id="check%{#attr.row_rowNum - 1}" value="%{#attr.row.chkBox}" fieldValue="%{#attr.row.aoId}" />
</display:column>
<display:column title="Action" style="width:10px;" value="Edit" href="vieweditorgs" paramId="aoId" paramProperty="aoId" />
<display:column title="View" style="width:10px;" value="View" href="vieworgs" paramId="aoId" paramProperty="aoId" />
<display:column title="Dlt" style="width:10px;" value="Dlt" href="singledeleteorgs" paramId="aoId" paramProperty="aoId" />
<display:column property="aoId" title="ID" />
<display:column property="aoName" title="Name" />
</display:table>
You need to define action in requesturi programmatically.
Please see this
dispalay tag table pass value to requestURI
In action class
private String myActionName;
public String search() {
organisationSearch = new OrganisationSearch();
organisationSearch.setAoName(aoName);
orglist = orgBo.searchOrg(organisationSearch);
//set action name
myActionName="action1.action";
return "search";
}
//other methods
public void setMyActionName(String myActionName) {
this.myActionName = myActionName;
}
public String getMyActionName() {
return myActionName;
}
In jsp file
<display:table id="u" name="userlist" pagesize="10" requestURI="${myActionName}" >
...
</display:table>
If I misunderstood your question, Please let me know.
I am facing a problem when trying to export a DataTable with some columns, both the DataTable and the Column components are composite elements, like this:
Custom dataTable XHTML (v:dataTable):
<cc:interface>
<cc:attribute name="value" required="true" />
<cc:attribute name="selectionMode" default="multiple" />
<cc:attribute name="selectionBean" />
<cc:attribute name="selectionProperty" />
<cc:facet name="header" />
</cc:interface>
<cc:implementation>
<p:dataTable id="teste" var="tableItem" value="#{cc.attrs.value}"
selection="#{cc.attrs.selectionBean[cc.attrs.selectionProperty]}"
rowKey="#{tableItem.id}" rowsPerPageTemplate="15, 30, 45"
paginator="true" rows="15"
emptyMessage="#{messages['dataTable.emptyMessage']}">
<cc:insertChildren />
<f:facet name="footer">
<p:commandButton value="#{messages['dataTable.exportExcel']}"
ajax="false">
<p:dataExporter type="xls" target="teste" fileName="export" />
</p:commandButton>`enter code here`
</f:facet>
</p:dataTable>
</cc:implementation>
Custom column XHTML (v:dataColumn):
<cc:interface
componentType="com.example.VDataColumn">
<cc:attribute name="value" />
</cc:interface>
<cc:implementation>
<c:choose>
<c:when test="#{cc.childCount gt 0}">
<cc:insertChildren />
</c:when>
<c:otherwise>
<h:outputText value="#{cc.attrs.value}" />
</c:otherwise>
</c:choose>
</cc:implementation>
The Column component is an extension of the org.primefaces.component.column.Column class:
package com.example.component;
import javax.faces.component.FacesComponent;
import javax.faces.component.NamingContainer;
import javax.faces.component.UINamingContainer;
import org.primefaces.component.column.Column;
#FacesComponent("com.example.VDataColumn")
public class VDataColumn extends Column implements NamingContainer {
#Override
public String getFamily() {
return UINamingContainer.COMPONENT_FAMILY;
}
}
The DataTable and Column are used as it follows:
<v:dataTable
value="#{testController.resultList}"
selectionBean="#{testController}"
selectionProperty="selectedList" selectionMode="multiple">
<p:column value="#{tableItem.id}" headerText="ID" />
<v:dataColumn value="#{tableItem.code}" headerText="Code" />
<v:dataColumn value="#{tableItem.nome}" headerText="Name" />
<v:dataColumn value="#{tableItem.desc}" headerText="Desc" />
</v:dataTable>
When I try to export the dataTable with the dataExporter that is inside the component, I get just one column in the XLS file, and it is only the p:column.
Debugging the primefaces DataExporter class, i noticed that the DataTable object contains 4 objects in the getChildren() method, one Column and 3 VDataColumn's, and only the Column object contains children itself.
Did anybody have the same issue? I am using Primefaces 4.0
I had same problem with a custom component. We resolve by extending the exporter and using custom validation for the component.
if (component instanceof UINamingContainer) {
UINamingContainer uiNamingContainer = (UINamingContainer) component;
UIComponent panel = uiNamingContainer.getFacet(UIComponent.COMPOSITE_FACET_NAME);
Collection<UIComponent> children = panel.getChildren();
for (UIComponent uiComponent : children) {
if (uiComponent instanceof javax.faces.component.html.HtmlOutputText) {
try {
uiNamingContainer.encodeBegin(context);
return super.exportValue(context, uiComponent);
} catch (IOException e) {
LOGGER.error(e);
} finally {
try {
uiNamingContainer.encodeEnd(context);
} catch (IOException e) {
LOGGER.error(e);
}
}
}
}
}
I'm testing the component "SelectOneMenu" on a jsf page. I'm populating this component dinamically though my ManageBean (that will get all Animals from database).
I would like to know if is possible to see the user selected item of that "SelectOneMenu" (combobox), I'm trying with value="#{animalsManage.animalSelect}" but it is only called on the beginning of the page. Also, I'm using an inputText to see the value of the selected intem of the "SelectOneMenu".
What I'm doing wrong?
JSF:
<body>
<ui:component>
<h:form>
<h:outputText value="Select one Mets File" />
<h:selectOneMenu id="combo" value="#{animalsManage.animalSelected}">
<f:selectItem itemLabel="Select..." noSelectionOption="true"/>
<f:selectItems value="#{animalsManage.allAnimals}" />
</h:selectOneMenu>
<h:inputText id="textbox" value="#{animalsManage.animalSelected }" />
</h:form>
</ui:component>
</body>
ManageBean:
#ManagedBean
#ViewScoped
public class AnimalsManage implements Serializable {
#EJB
private AnimalsFacadeREST animalsFacadeREST;
private String animalSelected;
private List< SelectItem> selectAnimals;
public List<SelectItem> getAllAnimals() {
List<Animals> al = animalsFacadeREST.findAll();
selectAnimals = new ArrayList< SelectItem>();
int i = 0;
for (Animals animal: al) {
selectAnimals.add(new SelectItem(i, animal.getName()));
i++;
}
return selectAnimals;
}
public String getAnimalSelected() {
return animalSelected;
}
public void setAnimalSelected(String animalSelected) {
this.animalSelected = animalSelected;
}
}
There are many solutions to the presented problem. I present here two basic ideas.
Server-side solution. Simply attach <f:ajax> tag inside your <h:selectOneMenu> to update selected values and rerender user's choice, like in
<h:selectOneMenu id="combo" value="#{animalsManage.animalSelected}">
<f:selectItem itemLabel="Select..." noSelectionOption="true"/>
<f:selectItems value="#{animalsManage.allAnimals}" />
<f:ajax execute="combo" render="textbox" />
</h:selectOneMenu>
<h:inputText id="textbox" value="#{animalsManage.animalSelected }" />
If you like, you may also do some custom logic with selected element in ajax listener by specifying listener="#{animalsManage.performCustomAjaxLogic}" of <f:ajax> tag.
Client-side solution. Simply update element with id="textbox" on basic change event. So, if you use jQuery the solution will be
$('#combo').change(function() {
$('#textbox').val($('#combo').val());
});
Thought the client-side solution will bind only text value of your input component.