f:ajax firing only once - ajax

I have a a form loading a list from my database. I can update, and delete the row i select and that is working fine. Now I added a start and stop button to each row to enable start an engine from another application. Now what I want to do is when i click on start ,my engine would start based on that row and that row would hide the start button and show the stop button.
I have implemented ajax on those columns in the row but it updates all rows at once and the ajax only triggers once.
What am I doing wrong here and can you show me the best way to press on start and then hide my start-button and show my stop-button or press on stop and hide my stop-button and show my start-button on that particular row.
snippet of codes in my managedbean
#ManagedBean
#SessionScoped
public class HibernateController {
private ArrayList<IPAddress> ipAddresses;
private Logger logger = Logger.getLogger(getClass().getName());
private boolean isStarted = false;
private boolean isStopped = true;
public HibernateController(){
ipAddresses = new ArrayList<IPAddress>();
}
public boolean engineIsStarted() {
return isStopped;
}
public boolean engineIsStopped() {
return isStarted;
}
public void startEngine(AjaxBehaviorEvent event){
System.out.println("I am here and started");
isStarted = true;
isStopped = false;
}
public void stopEngine(AjaxBehaviorEvent event){
System.out.println("I am here and stopped");
isStopped = true;
isStarted = false;
}
Snippet of codes in my xhtml
<h:form>
<h:dataTable value="#{hibernateController.ipAddresses}" var="tempAddress"
styleClass="demo-table"
headerClass="demo-table-header"
rowClasses="demo-table-odd-row,demo-table-even-row">
<h:column>
<!-- the column header -->
<f:facet name="header">IP Adress</f:facet>
<!-- the value for each row -->
#{tempAddress.ipAddress}
</h:column>
<h:column>
<!-- the column header -->
<f:facet name="header">Port Number</f:facet>
<!-- the value for each row -->
#{tempAddress.portNumber}
</h:column>
<h:column>
<!-- the column header -->
<f:facet name="header">Action</f:facet>
<!-- the value for each row -->
<h:commandLink value="Update"
action="#{hibernateController.loadAddress(tempAddress.id)}"/>
|
<h:commandLink value="Delete"
onclick="if (!confirm('Are you sure you want to delete this address?')) return false"
action="#{hibernateController.deleteAddress(tempAddress.id)}"/>
</h:column>
<h:column>
<h:commandButton id="startButton" value="start" rendered="#{hibernateController.engineIsStarted()}">
<f:ajax event="click" execute="#this" listener="#{hibernateController.startEngine}" render="#all" />
</h:commandButton>
<h:commandButton id="stopButton" value="stop" rendered="#{hibernateController.engineIsStopped()}">
<f:ajax event="click" execute="#this" listener="#{hibernateController.stopEngine}" render="#all" />
</h:commandButton>
</h:column>
</h:dataTable>
</h:form>
Image of interface now

Related

Primefaces 8.0 Datatable with Dynamic Model and Columns

I have a primefaces dataTable that displays data from several database tables. A selection list allows the user to select the specific database table to display. It works as expected except when the dataTable filtering capability is used. For example, when a user selects 'DEPT' from the selection list, the dataTable is rendered with data from the DEPT table. The user can select other tables normally. However, if the user selects another table called 'EMP' after filtering, the dataTable fails to render with the following exception:
javax.el.PropertyNotFoundException: The class 'example.dto.Dept' does not have the property 'firstName'.
at javax.el.BeanELResolver.getBeanProperty(BeanELResolver.java:576)
at javax.el.BeanELResolver.getValue(BeanELResolver.java:291)
at com.sun.faces.el.DemuxCompositeELResolver._getValue(DemuxCompositeELResolver.java:156)
Here's the .xhtml file:
<h:form prependId="false">
<p:outputLabel for="selTbl" value="Select a table:" />
<p:autoComplete id="selTbl" value="#{mainBean.selectedTable}"
completeMethod="#{mainBean.filterAuditTables}" cache="true" dropdown="true" effect="fade"
minQueryLength="3" forceSelection="true" size="35" style="margin-left: 10px;">
<p:ajax event="itemSelect" listener="#{mainBean.onTableSelect}" process="#this" update="#form" />
</p:autoComplete>
<p:dataTable id="audTblData" value="#{mainBean.data}" var="row"
filteredValue="#{mainBean.filteredData}" resizableColumns="true" resizeMode="expand"
sortMode="multiple">
<f:facet name="header">
<h:outputText value="#{mainBean.selectedTable}" />
</f:facet>
<p:columns value="#{mainBean.tableColumns}" var="col" sortBy="#{row[col.property]}"
filterBy="#{row[col.property]}" filterMatchMode="contains">
<f:facet name="header">
<h:outputText value="#{col.header}" />
</f:facet>
<h:outputText value="#{row[col.property]}" />
</p:columns>
</p:dataTable>
</h:form>
MainBean.java:
#Named
#ViewScoped
public class MainBean implements Serializable {
private static final long serialVersionUID = 1L;
// these are used for the audited table selection list
private List<String> auditedTables;
private String selectedTable;
// these are used in the table that displays the audit data
private List<ColumnModel> tableColumns;
private List<Auditable> data;
private List<Auditable> filteredData;
#Inject
private AudviewService audviewService;
#PostConstruct
public void init() {
auditedTables = audviewService.getAuditedTables();
}
public List<String> filterAuditTables(String query) {
return auditedTables
.stream()
.filter(t -> t.contains(query.toUpperCase()))
.collect(Collectors.toList());
}
public void onTableSelect(SelectEvent<String> event) {
retrieveTableData();
}
public void retrieveTableData() {
List<String> columns = audviewService.listTableColumns(selectedTable);
// initialize columns for <p:dataTable>
tableColumns = new ArrayList<ColumnModel>();
for (String col : columns) {
tableColumns.add(new ColumnModel(col, AudviewUtil.columnToProperty(col)));
}
// retrieve data for the selected table
data = audviewService.getTableData(selectedTable);
}
/* getters and setters */
}
Note that Auditable is an interface implemented by Dept.java and Emp.java.
As you noticed, the problem is switching from a filtered or sorted datatable to another, if the filtered or sorted column is a field that isn't in the new selected class. An easy solution would be moving all the needed fields into the superclass Auditable.
Another approach is separating datatable resetting&updating in two steps, here a possible solution (I replace, for testing purpose, your service with static code, so there could be some errors adapting my solution to your code):
xhtml
<h:form id="formTbl" prependId="false">
<p:outputLabel for="selTbl" value="Select a table:" />
<p:autoComplete id="selTbl" value="#{mainBean.selectedTable}"
completeMethod="#{mainBean.filterAuditTables}" cache="true"
dropdown="true" effect="fade" minQueryLength="3"
forceSelection="true" size="35" style="margin-left: 10px;">
<p:ajax event="itemSelect" listener="#{mainBean.onTableSelect}"
process="#this" onstart="PF('vtWidget').clearFilters()" />
</p:autoComplete>
<p:remoteCommand name="btn" process="#this" update="audTblData" />
<p:dataTable id="audTblData" value="#{mainBean.data}" var="row"
filteredValue="#{mainBean.filteredData}" resizableColumns="true"
resizeMode="expand" sortMode="multiple" widgetVar="vtWidget">
<f:facet name="header">
<h:outputText value="#{mainBean.selectedTable}" />
</f:facet>
<p:columns value="#{mainBean.tableColumns}" var="col"
sortBy="#{row[col.property]}" filterBy="#{row[col.property]}"
filterMatchMode="contains">
<f:facet name="header">
<h:outputText value="#{col.header}" />
</f:facet>
<h:outputText value="#{row[col.property]}" />
</p:columns>
</p:dataTable>
</h:form>
java
public void retrieveTableData() {
List<String> columns = listTableColumns(selectedTable);
// initialize columns for <p:dataTable>
tableColumns = new ArrayList<ColumnModel>();
for (String col : columns) {
tableColumns.add(new ColumnModel(col + " header", col));
}
// retrieve data for the selected table
data = getData(selectedTable);
DataTable dataTable = (DataTable) FacesContext.getCurrentInstance().getViewRoot().findComponent("formTbl:audTblData");
if (dataTable != null) {
dataTable.reset();
}
PrimeFaces.current().executeScript("btn()");
}
Pay attention, if you need also to manage pagination.

p:commandButton action not invoked after and ajax update

I have a JSF page which has a p:commandButton which has ajax=true and renders a p:panel which is wrapped in p:outputPanel when clicked. When this button is clicked the action method will set showCreateUser value in ManagedBean to true and this is used to render the Panel. This works fine - on button click the panel is rendered properly. Inside the p:panel there is another p:commandButton. This commanButton is not working as nothing happens when I click on it. The action method is never invoked. When I debug I realised that even though the ajax action sets showCreateUser to true but when I click on second button the showCreateUser value is false. So, the panel panel rendered=false and so the action is never invoked. Following are the xhtml and managedbean class. How can I resolve this? Thanks for your help!
registration.xhtml
<h:form id="userForm" style="background-color:white;border:0px; width:90%;">
<p:messages id="messagesForDebugging"
showDetail="true"
autoUpdate="true" />
<ui:debug hotkey="x"/>
<div style="margin-bottom: 10px;">
<p:commandButton id="btnConfirmYes" value="Yes" ajax="true" update="userRegOutPanel"
action="#{regBean.confirmYes}" styleClass="button" style="height:35px;">
<!-- <f:ajax render="userRegOutPanel" execute="userRegOutPanel"/> -->
</p:commandButton>
<p:commandButton id="btnConfirmNo" value="No" ajax="false"
action="#{regBean.confirmNo}" styleClass="button" style="height:35px;"/>
</div>
<p:outputPanel id="userRegOutPanel">
<p:panel id="userRegPanel" rendered="#{regBean.showCreateUser}">
<p:panelGrid id="userRegPanelGrid">
<p:row>
<p:column style="width:40%;background-color:#00a5b6;-moz-border-radius: 10px;-webkit-border-radius: 10px;-khtml-border-radius: 10px;border-radius: 10px;text-align:left;">
<h:inputHidden id="ssn" value="#{regBean.ssn}"/>
<p:panelGrid>
<p:row>
<p:column>
<p:commandButton value="Submit" ajax="true" action="#{regBean.submitRegistration}"
styleClass="button" style="width:140px;height:35px;" type="submit"/>
</p:column>
</p:row>
</p:panelGrid>
</p:column>
</p:row>
</p:panelGrid>
</p:panel>
</p:outputPanel>
</h:form>
Managed Bean
#ManagedBean
#ViewScoped
public class RegBean implements Serializable{
private static final long serialVersionUID = 1L;
static Logger log = LoggerFactory.getLogger(RegBean.class);
private String ssn;
private boolean showCreateUser = false;
public void confirmYes(){
setShowCreateUser(true);
}
public String confirmNo(){
log.info("In retrieveRegistration");
FacesContext fc = FacesContext.getCurrentInstance();
fc.addMessage("registrationError", new FacesMessage(
FacesMessage.SEVERITY_ERROR,
"Error. Contact customer service",
"Error. Contact customer service"));
return "/registration/registrationError";
}
public String submitRegistration() {
log.info("In submitRegistration");
FacesContext fc = FacesContext.getCurrentInstance();
return "/secured/home";
}
public String getSsn() {
return ssn;
}
public void setSsn(String ssn) {
this.ssn = ssn;
}
public boolean isShowCreateUser() {
return showCreateUser;
}
public void setShowCreateUser(boolean showCreateUser) {
this.showCreateUser = showCreateUser;
}
}
<p:commandButton id="btnConfirmNo" value="No" ajax="false"
action="#{regBean.ConfirmNo}"
styleClass="button" style="height:35px;"/>
In above code ,you've set action to be "ConfirmNo". I don't see any method as such.
Change above code as :
<p:commandButton id="btnConfirmNo" value="No" ajax="false"
action="#{regBean.agentConfirmNo}"
styleClass="button" style="height:35px;"/>
Now, it will invoke the method agentConfirmNo from your registration bean.
I hope that helps.

Start a method through a table row

I'm french, I will do in my best to speack english with you.
I have a datatable with books and information books.
I want my table to create a button for adding my book to my order (Order myOrder) but I can not, despite my attempts to do so.
My facelet :
<div class="divListLivres">
<h1>Liste des livres</h1>
<h:dataTable styleClass="order-table"
headerClass="order-table-header"
rowClasses="order-table-odd-row,order-table-even-row" var="_book"
value="#{catalogueIBean.books}">
<h:column>
<f:facet name="header">Titre</f:facet>
<h:outputLabel value="#{_book.title}" />
</h:column>
<h:column>
<f:facet name="header">Editeur</f:facet>
<h:outputLabel value="#{_book.editor}" />
</h:column>
<h:column>
<f:facet name="header">Auteur</f:facet>
<h:outputLabel value="#{_book.author.firstName}" />
<h:outputLabel value=" #{_book.author.lastName}" />
</h:column>
<h:column>
<f:facet name="header">Prix unitaire</f:facet>
<h:outputLabel value=" #{_book.unitPrice}" />
<h:outputLabel value="€" />
</h:column>
</h:dataTable>
</div>
Can you help me? Either by redirecting the action to a method of my bean (CatalogueIBean whith method "addOrder(){}") making sure to add the line directly in my object "Order myOrder." Thanks !
you can easily add another column of a command button to your datatable in that way you will also have a button in each row which can redirect you to your required method
<p:column style="width:6%" headerText="Add to Order">
<p:commandButton id="addOrderButton"
action="#{catalogueIBean.addOrder}" immediate="true" ajax="true"
icon="ui-icon-folder-open">
<f:param name="id" value="#{_book.id}" />
</p:commandButton>
</p:column>
note: you can change the icon as you want or remove if you dont want an icon instead you can name the button by the value attribute of the button. Also if you dont want your button to be in your data table you can make a new form outside the form of data table and add your button there.
your backing bean should be
FacesContext context = FacesContext.getCurrentInstance();
Map requestMap = context.getExternalContext().getRequestParameterMap();
String value = (String) requestMap.get("id");
Integer id = Integer.parseInt(value);
now that you have the id of each row you can traverse to your required object
The fonctione "AddOrder" does not start but my method "init ()" yes.
I want to retrieve the "order" object of my line, I do not see how that is possible here.
It should incorporate something for the ajax work?
Here is the beginning of my bean:
#ManagedBean(name = "catalogueIBean")
#RequestScoped
public class CatalogueIBean {
#Inject
private FacesContext facesContext;
#Inject
private BookService bookService;
// ////////////////Variables de facelet//////////////////
private String title;
private String isbn13;
private Double price;
private int selectAuthor;
private List<Author> authors;
private String selectEditor;
private List<SelectItem> editorNames;
private List<Book> books;
private Book selectedBook;
// ////////////////Méthodes de facelet//////////////////
public String addOrder(/*parameter ??*/) throws Exception {
//add order of the line of datatable in my order (or create an orderLine)
return null;
}
// ////////////////Initialisation//////////////////
#PostConstruct
public void init() throws Exception {
.......
}
thank you

Dynamic input fields (values) reset on remove item/field

I have a dynamically expansible table with an add and remove button:
<h:form>
<h:dataTable id="tblFields" value="#{bean.fields}" var="field">
<h:column>
<h:inputText value="#{field.value}" />
</h:column>
<h:column>
<h:inputText value="#{field.value2}" />
</h:column>
<h:column>
<h:inputText value="#{field.value3}" />
</h:column>
<h:column>
<h:commandButton value="Remove">
<f:ajax listener="#{bean.onButtonRemoveFieldClick(field)}" immediate="true" render="#form" />
</h:commandButton>
</h:column>
</h:dataTable>
<h:commandButton value="Add">
<f:ajax listener="#{bean.onButtonAddFieldClick}" execute="#form" render="tblFields" />
</h:commandButton>
</h:form>
This is the associated backing bean:
#Named
#ViewScoped
public class Bean {
private List<Field> fields;
#PostConstruct
public void init() {
fields = new ArrayList();
fields.add(new Field());
}
public List<Field> getFields() {
return fields;
}
public void setFields(List<Field> fields) {
this.fields = fields;
}
public void onButtonRemoveFieldClick(Field field) {
fields.remove(field);
}
public void onButtonAddFieldClick() {
fields.add(new Field());
}
}
The use case is as follows:
Press the add button multiple times.
Fill out all values.
Press the remove button of one random row.
After that, all values filled so far disappears and show up blank. How can I keep them filled after pressing the remove button?
It's because you're in the remove button ajax-updating the entire form without processing the newly submitted input values. The immediate="true" on ajax listener skips the processing of all input components which do not have immediate="true" set. You need to remove the attribtue. The absence of execute attribute will cause only the current component (#this) to be processed by default. You need to explicitly specify #form.
So, just do the same as in your add button. Replace immediate="true" by execute="#form".
<f:ajax listener="#{bean.onButtonRemoveFieldClick(field)}" execute="#form" render="#form" />

Navigate to another page on rowselect of datatable in primefaces

I have a primefaces datatable where number of records are displaying.
I want navigate to another page on the rowSelect event (to edit the selected entity for example).
The closest sample/demo I could find was use the p:ajax tag to bind the rowSelect event to a listener method
http://www.primefaces.org/showcase-labs/ui/datatableRowSelectionInstant.jsf
I also got one article for the same http://forum.primefaces.org/viewtopic.php?f=3&t=14664
, I tried to implement in same as they did.But it also didn't worked.
I am trying in this way and guide me If I missed anything.
<p:dataTable var="product" value="#{addPatientBB.patientAddList}" paginator="true" rows="10"
selection="#{addPatientBB.pat}" selectionMode="single">
<p:ajax event="rowSelect" listener="#{addPatientBB.onRowSelect}" />
<p:column>
<f:facet name="header">
<h:outputText value="FirstName" />
</f:facet>
<h:outputText value="#{product.firstName}" />
</p:column>
<p:column>
<f:facet name="header">
<h:outputText value="Email" />
</f:facet>
<h:outputText value="#{product.email}" />
</p:column>
<p:column>
<f:facet name="header">
<h:outputText value="Gender" />
</f:facet>
<h:outputText value="#{product.gender}" />
</p:column>
</p:dataTable>
And Backing bean is :
#ManagedBean
#ViewScoped
public class AddPatientBB implements Serializable
{
private Patient pat;
public Patient getPat()
{
System.out.println("tried to get pat");
return pat;
}
public void setPat(Patient pat)
{
this.pat = pat;
System.out.println("tried to set pat");
}
public void onRowSelect()
{
System.out.println("inside onRow select Method");
ConfigurableNavigationHandler configurableNavigationHandler = (ConfigurableNavigationHandler) FacesContext.getCurrentInstance().getApplication().getNavigationHandler();
System.out.println("navigation objt created");
configurableNavigationHandler.performNavigation("Page?faces-redirect=true");
// Page is my navigation page where I wish to navigate named as
// "Page.xhtml"
System.out.println("Navigation executed");
}
}
So how can I navigate to another page on rowselect event? and how can display its values after navigationg the form.
I am able to go inside onRowSelect() method , actually problem is he is not able to get or understood that path :
configurableNavigationHandler.performNavigation("Page?faces-redirect=true");
so he is not able to print any logs after this line.
why is it so? is it because of I am using Liferay?
Pla guide me.
Well i think the onRowSelect is never executed because you defined it wrong.
Try this:
public void onRowSelect(SelectEvent event)
{
FacesContext.getCurrentInstance().getExternalContext().redirect("page.xhtml?id=" +pat.getId());
}
If u are using FacesServlet then use.jsf instead of .xhtml
public void onRowSelect(SelectEvent event)
{
FacesContext.getCurrentInstance().getExternalContext().redirect("page.jsf?id="+pat.getId());
}

Resources