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;
}
Related
I have the following command button in the view with ID "save":
<p:panel style="border:none;text-align:left;margin:0;">
<p:commandButton value="Save Document" id="save" icon="fa fa-save"
disabled="#{dIGRCController.digrc.qconce == '020'}">
<f:param name="validate" value="true" />
</p:commandButton>
<p:commandButton value="Clear" icon="fa fa-undo"></p:commandButton>
</p:panel>
I am trying to dynamically assign a different actionListener. If the user wants to INSERT some new record, I want it to call the insert method. If the user wants to update an existing record, it should call the update method.
Right now I am trying to do this:
#PostConstruct
public void init() {
// setting the action listener of the Save Document button
UIViewRoot viewRoot = FacesContext.getCurrentInstance().getViewRoot();
// UIComponent button = viewRoot.findComponent("save");
CommandButton button = (CommandButton) viewRoot.findComponent("save");
FacesContext context = FacesContext.getCurrentInstance();
MethodExpression methodExpression = context
.getApplication()
.getExpressionFactory()
.createMethodExpression(context.getELContext(),
"#{dIGRCController.updateDocument}", null,
new Class[] { DIGRCController.class });
button.addActionListener(new MethodExpressionActionListener(
methodExpression));
}
I am getting a null pointer exception on the line:
button.addActionListener(new MethodExpressionActionListener(
methodExpression));
What am I doing wrong? Is there another way to accomplish what I am trying to do? I am using JSF 2.2, PrimeFaces 5.3 and OmniFaces 1.11.
The findComponent() takes a client ID as argument not a component ID. The client ID is exactly the value of the generated HTML id attribute associated with the component in question. In case of a command button, usually the component ID of the parent <h:form> is prepended, separated by the naming container separator character which defaults to :.
Given this,
<h:form id="form">
<p:commandButton id="save" ... />
</h:form>
the client ID would be form:save.
CommandButton button = (CommandButton) viewRoot.findComponent("form:save");
See also this related question as to identifying and using client ID: How to find out client ID of component for ajax update/render? Cannot find component with expression "foo" referenced from "bar"
Unrelated to the concrete problem, manipulating the component tree in Java side is a poor practice. You'd better keep using XHTML+XML for this which is so much more self-documenting as to declaring/defining tree structures. You can use JSTL tags to dynamically build the view (note: this is different from dynamically rendering the view using rendered attribute!).
E.g.
<p:commandButton ... action="#{bean.save}">
<c:if test="#{bean.existing}">
<f:actionListener binding="#{bean.needsUpdate()}" />
</c:if>
</p:commandButton>
See also JSTL in JSF2 Facelets... makes sense?
Even more, you could just pass #{bean.existing} as method argument.
<p:commandButton ... action="#{bean.save(bean.existing)}" />
Both approaches are in turn admittedly kind of weird if #{bean.existing} refers the same bean as #{bean.save}. You could just check for that inside #{bean.save} itself.
public void save() {
if (existing) {
// UPDATE
} else {
// INSERT
}
}
Going further on that, this is IMO not the responsibility of frontend layer, but of the service layer. You pass the whole entity to the service layer which in turn checks based on PK if it's existing or not.
if (entity.getId() == null) {
// INSERT
} else {
// UPDATE
}
I have a primefaces datatable and i have a column with filter.i would like to apply filter on the column from the backing bean.
I followed this example and i am able to get the input given filter text box into my bean.
but when i use setFilter ,the values are being set in the HashMap but filter is not being applied on the datatable.
Example column
<p:column filterBy="#{var.value}" headerText="Example" footerText="contains" filterMatchMode="contains" />
Bean is session scoped and the following code is in a function which gets called on a button click.
Map<String,String> theFilterValues = new HashMap<String,String>();
theFilterValues.put("filterColumn","someValue");
myDataTable.setFilters(theFilterValues);
this sets the values ,but there is no change on datatable.
i tried this but it did not help.
All i need is to set a filter on the datatable column upon a button click.
Thanks in advance
The values in the inputs of the DataTable filter are sent in the FacesContext request parameter map, and obtained by the DataTableRenderer when it is rendering the DataTable (see the encodeFilter method for PF 3.5, PF 4.0, or PF 6.1)
So, if your button is in the same form of the DataTable, the values of the filter are sent in the request parameter map, and the renderer will show those values over whatever else you want.
You'll need the button to be in a separate form:
<h:form>
<p:commandButton action="#{someBean.action()}" update="#([id$=dataTable])" />
</h:form>
<h:form>
<p:dataTable id="dataTable" [...] >
<p:column filterBy="#{var.col}" filterValue="#{someBean.filterValue}">
<h:outputText value="#{var.col}">
</p:column>
</p:dataTable>
</h:form>
And then, you can change the filterValue in the bean:
#Named
#SessionScoped
public SomeBean implements Serializable {
private String filterValue;
[...]
public void action() {
filterValue = "new value";
}
[getters/setters]
}
You can use a Map for the filterValues if you are using many filters.
As an alternative, if you need to redirect the user to a new page, you can put the values in the URL, instead of using filterValue. Example:
https://example.com/app/pageOfTheTable.xhtml?form:dataTable:colum:filter=new%20value
The part form:dataTable:colum:filter is the ID of the filter input. You can get that by inspecting the element using your browser. The principle is the same: you are using the request parameter map.
It may be useful to update the value of the backing bean when the user types something. I've found a patch here.
It basically changes populateFilterParameterMap method, in FilterFeature class, so it sets the value of the filterValue. You can put the added lines at the end of the for loop.
for ( ... ){
[...]
+ ValueExpression filterValueVE = column.getValueExpression("filterValue");
+ if (filterValueVE == null) {
+ ((UIComponent)column).getAttributes().put("filterValue", filterValue);
+ } else {
+ filterValueVE.setValue(context.getELContext(), filterValue);
+ }
}
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 am using primefaces 3.2.
I've got the following situation:
<h:form id="someForm">
..
<p:dataTable id="someDataTable" value="#{BackingBean.list}" var="element" ..>
<p:column>
<p:calendar id="someCalendar" value=#{element.date} ../>
<p:message id="someCalendarMessage" for=":someForm:someDataTable:someCalendar"/>
<p:column>
</p:dataTable>
..
</h:form>
The "someDataTable" is updated dynamically and then all the data are submitted to the server side. In the backing bean I want to send message for calendar "someCalendar" if the entered date doesn't satisfy some condition. I try to find the component using this code:
FacesContext facesContext = FacesContext.getCurrentInstance();
facesContext.addMessage(facesContext.getViewRoot().findComponent(":someForm:someDataTable:" + "i" + ":someCalendar").getClientId(), new FacesMessage(FacesMessage.SEVERITY_ERROR, Utils.getResourceBundleString("dictionary", "error") + ":", Utils.getResourceBundleString("dictionary", "some_message")));
return;
Where i is the index of the "element" in the dataTable which the same as index in the list located in the BackingBean.
The problem is that I get NullPointerException since the facesContext.getViewRoot().findComponent(..) method cannot find the component, although I checked the generated id of the calendar in the view and it is
:someForm:someDataTable:0:someCalendar for the first element and it should be :someForm:someDataTable:1:someCalendar for the next element etc.
Why the facesContext.getViewRoot().findComponent(..) method cannot find the component inside the ? The is updated dynamically and maybe the server side doesn't get the updated component tree after submission is done?
Thanks in advance.
This is because the p:dataTable is a repeated component and during view build time there is only one calendar in the view root. It has the id someForm:someDataTable:someCalendar.
Only during view render time the table rows are created and the row-dependent ids generated.
You should use JSF build-in validation facilities to check your dates:
in the view:
<p:calendar id="someCalendar" value=#{element.date}
validator="#{BackinBean.validateDate}"/>
<p:message id="someCalendarMessage" for="someCalendar"/>
(someCalendar in the for attribute is sufficient)
and in the backing bean:
public void validateDate(
FacesContext context,
UIComponent component,
Object value) throws ValidatorException {
if (/* date is not valid */) {
throw new ValidatorException(
new FacesMessage("Date is not valid"));
}
}
The FacesMessage from the validation method will automatically be displayed in the correct table row.
I am stuck in a rather weird situation.
I have a requirement in which i need a tree structure to define a list of elements. And when we click on any of those elements in a tree. it should expand the section below it to show 2 side by side datatables which are linked to that element.
I can use JSF 2.0 core or even primefaces 3.1.
Is it possible ??
Could anyone please help ... any suggestions would be appreciated.
Updated
My model is something like :
class Shop{
boolean isoperational;
String name;
List<Item> items;
List<boolean> itempresent;
List<Employee> employees;
}
I need the name of the shop on the tree node along with the isoperational checkbox;
And when we click on that node it should open 2 datatables.
One containing the List of items along with itempresent checkbox.
Other containing the List of employees.
Thanks
Edited per your response (if i understand you correctly). Note that this is written from head so some attribute names might differ. The point is to set an active collection from your treetable depending on which row is clicked. An ID is set via the actionListener, then the action sets mycontroller.activeCollection to the list you want to show. Then the datatable is rerendered via normal post or ajax with values depending on which row you clicked.
Markup
<p:treeTable value="#{myController.treenode}" var="item">
<p:column>
<h:commandLink action="#{myController.setActiveShop}" value="set">
<f:setPropertyActionListener target="#{myController.shipName}" value="#{item.shop.name}"/>
</h:commandButton>
</p:column>
</p:treeTable>
<p:dataTable value="#{myController.activeShop.items" rendered="#{!empty myController.activeShop}" var="item">
<p:column>#{item.name}</p:column>
</p:datatable>
<p:dataTable value="#{myController.activeShop.employees" rendered="#{!empty myController.activeShop}" var="item">
<p:column>#{item.name}</p:column>
</p:datatable>
Controller
#ManagedBean
#ViewScoped // Or #SessionScoped... something that can cache lists, not sure how this would be done with requestscope
public class MyController{
private List<Shop> shopList; // Set this from a datasource. Or use only shopTree below to store your shops..
private Shop activeShop;
private String shopName;
private TreeNode shopTree; // Generate this from shopList
// insert getters and setters
private setActiveShop(){
for(Shop s : shipList)
if(s.getName().equals(shopName)
activeShop = s;
}
}