How to render a datatable in JSF with AJAX clicking a commandButton - jsf

The objective is to have a h:commandButton and once I have clicked it, using AJAX it will show the datatable "listaActores" (initially not showing it).
How could i do this? I have search for a solution, but I only found how to re-render the table once is present. My current code shows the table without doing nothing and clicking the button doesn't do anything.
<h:form>
<h:commandButton id="submit" value="Submit">
<f:ajax event="click" execute="#this" render="listaActores" />
</h:commandButton>
<h:dataTable id="listaActores" border="1"
value="#{peliculasEditarBean.listaActores}" var="actor">
<h:column>
<f:facet name="header">NOMBRE</f:facet>
#{actor.nombre}
</h:column>
<h:column>
<f:facet name="header">APELLIDO</f:facet>
#{actor.apellido}
</h:column>
</h:dataTable>
</h:form>

Your question is somewhat incomplete, but I'll answear anyway. Two things:
You're not saying how the table is "initially not showing". If there is some rendered on it, than you need to know that you must render a parent of the table. You can render only things that exist in rendered HTML. See for example this answer.
If you'll put action in the button you'll see that the AJAX won't work. You need to change event to action or delete this attribute to use a default.
I preperend simple working example (BTW. Welcome on Stackoverflow :-) If you want get help faster Minimal, Reproducible Example should be your's part of a question :-)):
(XHTML, added action to commandButton and remove event in f:ajax)
<h:form>
<h:commandButton id="submit" value="Submit"
action="#{peliculasEditarBean.initialize}">
<f:ajax execute="#this" render="listaActores" />
</h:commandButton>
<h:dataTable id="listaActores" border="1"
value="#{peliculasEditarBean.listaActores}" var="actor">
<h:column>
<f:facet name="header">NOMBRE</f:facet>
#{actor.nombre}
</h:column>
<h:column>
<f:facet name="header">APELLIDO</f:facet>
#{actor.apellido}
</h:column>
</h:dataTable>
</h:form>
(and bean)
#ManagedBean
#ViewScoped
public class PeliculasEditarBean implements Serializable {
private List<Actor> listaActores = null;
public List<Actor> getListaActores() {
return listaActores;
}
public void initialize() {
listaActores = new ArrayList<>(3);
listaActores.add(new Actor("foo", "bar"));
listaActores.add(new Actor("foo", "foo"));
listaActores.add(new Actor("bar", "bar"));
}
public class Actor {
private final String nombre;
private final String apellido;
Actor(String nombre, String apellido) {
this.nombre = nombre;
this.apellido = apellido;
}
public String getApellido() {
return apellido;
}
public String getNombre() {
return nombre;
}
}
}

Related

Dynamic update primefaces component according to a autocomplete value

Someone can explain how to update an certain component in a view (example: dataScroller, dataList etc) using an autocomplete component ? I'm trying something with the ajax event "itemSelect" but with no success on how to proceed, any example, explanation, light will be a good help.
Some code (xhtml page)
<h:form id="frmPesquisarModalidade">
<p:autoComplete id="autoModalidade" multiple="true" value="#{matriculaBean.modalidadesSelecionadas}" completeMethod="#{matriculaBean.completeModalidade}"
var="modalidade" itemLabel="#{modalidade.nome}" itemValue="#{modalidade}" forceSelection="true">
<f:converter binding="#{modalidadeConverter}"/>
<f:ajax listener="#{matriculaBean.onItemSelect}" event="itemSelect" render="test"/>
<p:column style="width:10%">
<h:outputText value="#{modalidade.nome}"/>
</p:column>
</p:autoComplete>
<p:dataScroller id="dataScrollModalidadesSelecionadas" value="#{matriculaBean.modalidadesSelecionadas}" var="modalidade" chunkSize="6">
<h:panelGrid columns="2" cellpadding="5" id="test">
<h:outputText value="#{modalidade.nome}"/>
</h:panelGrid>
</p:dataScroller>
</h:form>
backing bean
#Named
#ViewScoped
public class MatriculaBean {
private List<Modalidade> modalidadesDisponiveis;
private List<Modalidade> modalidadesSelecionadas;
#Autowired
private ServicoModalidade servicoModalidade;
#PostConstruct
private void init(){
modalidadesDisponiveis = servicoModalidade.listar();
}
public List<Modalidade> completeModalidade(String busca) {
List<Modalidade> filtrados = new ArrayList<Modalidade>();
for (Modalidade mod : modalidadesDisponiveis) {
if (mod.getNome().contains(busca)) {filtrados.add(mod);}
}
return filtrados;
}
public void onItemSelect(SelectEvent event){
//????????
}
What you need to do in onItemSelect method is update the value of the target component, based on the selected item.
If you want to update dataScrollModalidadesSelecionadas:
public void onItemSelect(SelectEvent event){
//Get the selected item value
Modalidade m = new Modalidade();
m = event.getObject();
//Create/use a List method which can search the DB based on the selected item
modalidadesDisponiveis = servicoModalidade.listarPorModalidade(m);
}
And in the JSF, you just have to update the target component:
<p:autoComplete ...... >
<p:ajax listener="#{matriculaBean.onItemSelect}" event="itemSelect" update="dataScrollModalidadesSelecionadas"/>
</p:autoComplete>
I'm not sure if those options and properties you defined gonna work as expected, but the example above is the basics to update a component based on ItemSelect.
Also, I prefer using <p:ajax> rather than <f:ajax>
<h:form id="frmPesquisarModalidade">
<p:autoComplete id="autoModalidade" multiple="true" value="#{matriculaBean.modalidadesSelecionadas}" completeMethod="#{matriculaBean.completeModalidade}"
var="modalidade" itemLabel="#{modalidade.nome}" itemValue="#{modalidade}" forceSelection="true">
<f:converter binding="#{modalidadeConverter}"/>
<p:ajax event="itemSelect" update="dataScrollModalidadesSelecionadas"/>
<p:column style="width:10%">
<h:outputText value="#{modalidade.nome}"/>
</p:column>
</p:autoComplete>
<p:dataScroller id="dataScrollModalidadesSelecionadas" value="#{matriculaBean.modalidadesSelecionadas}" var="modalidade" chunkSize="6">
<h:panelGrid columns="2" cellpadding="5">
<h:outputText value="#{modalidade.nome}"/>
</h:panelGrid>
</p:dataScroller>
</h:form>
solved!!! to resolve my issue i'd discovered theres no need to apply an backing bean logic withe the itemSelect event... just create an ajax event in the xhtml page and use the update attribute with the respective id! Thanks for help

jsf inputText only displayed value when is readonly true or outputText

I have a h:inputText with valueChangeListener, when the user type some code another h:inputText display data from MySQL about that code, the valueChangeListener works but the second h:inputText not displayed the value and only do it when I set the readonly attribute or I change the component to h:outputText
my facelets page is:
<h:form id="idFacturacion">
<rich:panel>
<f:facet name="header">
<h:outputText value="FACTURACION AL CLIENTE" />
</f:facet>
<h:panelGrid columns="4">
<h:outputText value="Cedula: " />
<h:inputText value="#{facturaBean.encFactura.cedula}" onchange="submit();" valueChangeListener="#{facturaBean.processValueChange}" />
<h:outputText value="Nombre: " />
<h:inputText value="#{facturaBean.encFactura.nombre_cli}" />
</h:panelGrid>
</rich:panel>
</h:form>
facturaBean is:
#ManagedBean
#SessionScoped
public class FacturaBean {
private EncFactura encFactura = new EncFactura();
//getter and setter
public void processValueChange(ValueChangeEvent event){
String ced = event.getNewValue().toString();
try{
//do the database thing
if(resultSet.next()){
encFactura.setNombre_cli(resultSet.getString("nombre_cli"));
}else{
encFactura.setNombre_cli("");
}
}catch(SQLException error){
facesContext.addMessage(null, new FacesMessage("Hubo un error SQL."));
}
}
}
Please see
Change inputText value from listener method… and
Possible to execute `valueChangeListener` for `p:inputText` without hitting `enter` key?
May I suggest using ajax?
Here is a primefaces example but you could apply to richfaces..
<h:inputText value="#{facturaBean.stringOne}" >
<p:ajax event="change" listener="#{facturaBean.processValueChange}" update="strTwo"/> </h:inputText> <h:outputText value="Nombre: " />
<h:inputText id="strTwo" value="#{facturaBean.stringTwo}" />
</h:panelGrid>
private String stringOne= "";
private String stringTwo= "";
public void processValueChange(){
stringTwo = stringOne;
}
With getters etc.. basically on change, fires off to ajax, you do your database call etc, then it returns the response and updates your other input field, it's a much cleaner way than trying to submit forms etc..
Also are you sure you want session scope?

Can't get filtering to work on PrimeFaces DataTable

I am trying to use filtering on my datatable. Whenever the table first loads, it looks like this:
If I enter text into the filter of user name, the table looks like this:
I would expect it to only show dangreen87 since mike.smith does not contain a "d". It however just displays no user names. Im not sure what this behaviour is?
I have a datatable like so:
<h:body>
<ui:composition>
<h:panelGroup layout="block" styleClass="messagesPanel" rendered="#{socialAdvertiserManagedBean.displaySearch}" >
<p:dataTable
resizableColumns="true"
var="account"
value="#{searchManagedBean.accountsToDisplay}"
scrollable="true"
paginator="true"
rows="10"
rowKey="#{account.id_value}"
emptyMessage="No accounts found for the given criteria"
widgetVar="searchTable"
filteredValue="#{searchManagedBean.filteredAccounts}">
<f:facet name="header">
#{searchManagedBean.isCompany ? 'Company' : 'Social Advertisers'}
</f:facet>
<p:column headerText="Image">
<p:graphicImage value="/dbimages/#{accountManagedBean.getImageId(account)}" width="25" height="25"/>
</p:column>
<c:if test="#{searchManagedBean.isCompany}" >
<p:column headerText="Company Name">
<h:outputLabel value="#{accountManagedBean.getCompany(account).name}" />
</p:column>
</c:if>
<c:if test="#{not searchManagedBean.isCompany}" >
<p:column id="userNameColumn" filterBy="#{account.userName}" filterMatchMode="contains">
<f:facet name="header">
<h:outputLabel value="User Name"/>
</f:facet>
<h:outputLabel value="#{account.userName}" />
</p:column>
</c:if>
</p:dataTable>
My Backing bean looks like so:
#ManagedBean
#ViewScoped
public class SearchManagedBean implements Serializable
{
private boolean isCompany;
private Account selectedAccount;
#EJB
private AccountDao accountDao;
#EJB
private SocialAdvertiserDao socialAdvertiserDao;
#EJB
private CompanyDao companyDao;
private List<Account> filteredAccounts;
#PostConstruct
public void init()
{
isCompany = true;
}
public List<Account> getAccountsToDisplay()
{
List temp;
if(isCompany)
{
temp = companyDao.findAll();
}
else
{
temp = socialAdvertiserDao.findAll();
}
return temp;
}
public List<Account> getFilteredAccounts() {
return filteredAccounts;
}
public void setFilteredAccounts(List<Account> filteredAccounts) {
this.filteredAccounts = filteredAccounts;
}
public boolean getIsCompany() {
return isCompany;
}
public void setIsCompany(boolean isCompany) {
this.isCompany = isCompany;
}
....
Those JSTL <c:if> tags bound to a view scoped bean property is the culprit.
<c:if test="#{not searchManagedBean.isCompany}" >
<p:column id="userNameColumn" filterBy="#{account.userName}" filterMatchMode="contains">
...
</p:column>
</c:if>
Long story short, carefully read #ViewScoped fails in taghandlers and JSTL in JSF2 Facelets... makes sense? In a nutshell, it causes the view scoped bean to be recreated on every single HTTP request and therefore a complete reset of the bean's state across the filtering and sorting ajax requests.
This #ViewScoped+taghandler issue is solved since Mojarra 2.1.18. Basically, you'd need to upgrade to at least Mojarra 2.1.18 (it's currently already at 2.1.25). However, this is after all not the canonical approach. You should just use the rendered attribute of <p:column> for that.
<p:column id="userNameColumn" filterBy="#{account.userName}" filterMatchMode="contains" rendered="#{not searchManagedBean.isCompany}">
...
</p:column>

JSF datatable: adding and removing rows clear rows values

I have a h:datatable showing a list of rows, and the fields of each row are input fields.
I render an "Add Row" button before the table, and a "Remove Row" button on each row of the table.
The baking bean is viewScoped, and the buttons add/remove elements from the java list in the backing bean, and then return to the same view.
I set the immediate attribute to "true" in the buttons in order to not validate the input fields when I add or remove a row.
Everything works ok but one thing: the values of the input fileds are cleared. I thought that the view kept the values beacuse the bean is viewScoped.
How can I achieve adding/removing rows without triggering validations and keeping the values that were already typed by the user in the form?
My view:
<h:form>
<h:commandButton value="Añadir Fila" immediate="true" action="#{tablaController.addRowAction}" />
<h:dataTable value="#{tablaController.lista}" var="fila" cellpadding="0" cellspacing="0" border="1">
<f:facet name="header">TABLA</f:facet>
<h:column>
<f:facet name="header"><h:outputLabel value="NOMBRE" /></f:facet>
<h:inputText id="nom" value="#{fila.nombre}" />
<h:message for="nom" class="msjError" />
</h:column>
<h:column>
<f:facet name="header"></f:facet>
<h:commandButton value="Quitar Fila" immediate="true" action="#{tablaController.removeRowAction(fila)}" />
</h:column>
</h:dataTable>
</h:form>
My backing bean:
#ManagedBean(name="tablaController")
#ViewScoped
public class TablaController {
private List<Fila> lista;
...
public TablaController() { }
...
#PostConstruct
public void init() {
this.lista = new ArrayList<Fila>();
for (int i=0; i<5; i++) {
Fila fila = new Fila();
fila.setNombre("");
this.lista.add(i,fila);
}
}
...
public String addRowAction () {
Fila fila = new Fila();
fila.setNombre("");
this.lista.add(fila);
return "";
}
public String removeRowAction (Fila f) {
boolean exito = this.lista.remove(f);
return "";
}
...
}
UPDATE --> MY SOLUTION:
I write here my solution if someone is interested.
The problem is that I use immediate="true" to skip validations, but this makes to skip the update_model_values too, so that the values entered by the user in the form are lost after clicking the add/remove buttons and re-redenring the page.
As I use "JSR-303 bean validation", my solution was to skip validations using the f:validateBean to enable/disable them. Depending on the button I click, if I want the validations to execute, I enable the bean validation (for example in a "submit" button), and if I want to skip them, I disable bean validation (like in the add/remove row buttons). But anyway the update_model_values always executes, so the values are not lost.
Here's the view:
<h:form>
<f:validateBean disabled="#{!empty param['disableValidation']}">
<h:commandButton value="Añadir Fila" action="#{tablaController.addRowAction}">
<f:param name="disableValidation" value="true" />
</h:commandButton>
<h:dataTable value="#{tablaController.lista}" var="fila" cellpadding="0" cellspacing="0" border="1">
<f:facet name="header">TABLA</f:facet>
<h:column>
<f:facet name="header"><h:outputLabel value="NOMBRE" /></f:facet>
<h:inputText id="nom" value="#{fila.nombre}" />
<h:message for="nom" class="msjError" />
</h:column>
<h:column>
<f:facet name="header"></f:facet>
<h:commandButton value="Quitar Fila" action="#{tablaController.removeRowAction(fila)}">
<f:param name="disableValidation" value="true" />
</h:commandButton>
</h:column>
</h:dataTable>
<h:commandButton value="Submit" action="#{tablaController.saveData}" />
</f:validateBean>
</h:form>
The backing bean:
#ManagedBean(name="tablaController")
#ViewScoped
public class TablaController {
private List<Fila> lista;
...
public TablaController() { }
...
#PostConstruct
public void init() {
this.lista = new ArrayList<Fila>();
for (int i=0; i<5; i++) {
Fila fila = new Fila();
fila.setNombre("fila "+i);
this.lista.add(i,fila);
}
}
...
public String addRowAction () {
Fila fila = new Fila();
fila.setNombre("");
this.lista.add(fila);
return "";
}
public String removeRowAction (Fila f) {
this.lista.remove(f);
return "";
}
...
public String saveData () {
...
//processes the valid data
//for example, calls to a service method to store them in a database
...
return "";
}
...
}
I set the immediate attribute to "true" in the buttons in order to not validate the input fields when I add or remove a row.
immediate="true" is the wrong tool for the job. It should be used to prioritize validation, not to enable/disable validation. The difference is rather huge as you encountered yourself.
You want to trigger validation conditionally. In case of e.g. required="true" that'd be as easy as
<h:inputText ... required="#{saveButtonPressed}" />
where #{saveButtonPressed} evaluates true when the save button is pressed. E.g. when its client ID is present in request parameter map.
In case of JSR 303 bean validation, that'd be a matter of
<f:validateBean disabled="#{not saveButtonPressed}">
<h:inputText ... />
</f:validateBean>
or with OmniFaces <o:validateBean> which allows controlling that on a per-command basis.
<h:commandButton id="add" ...>
<o:validateBean disabled="true" />
</h:commandButton>
I had exactly the same problem. In short, you can NOT use immediate for action that update data table(UIData) or facelet repeat. Short explanation:submitted values are not kept for re-display if inputs in UIData do not go through validation. Long explanation can be found here: long explanation and a related bug in Mojarra

JSF commandbutton id inside datatable

How can I add in commandbutton inside datatable?
<hx:dataTableEx value="#{searchData.searchFriends}" var="s">
<hx:columnEx>
<f:facet name="header">
<h:outputText value="First Name" />
</f:facet>
<hx:requestLink action="#{pc_Search.doAddFriendAction}">
<h:outputText value="Add as Friend" />
<f:param name="friendId" value="#{s.memberId}" />
</hx:requestLink>
</hx:columnEx>
</hx:dataTableEx>
To get the data at backend
String friendId = (String)getRequestParam().get("friendId");
But once I change the requestlink to command button the friedId = null? any idea how can i pass value using command button
Wrap the datatable value in a DataModel. Then you can obtain the selected row by DataModel#getRowData().
public class Bean {
private List<Friend> friends;
private DataModel friendsModel;
public Bean () {
friends = getItSomehow();
friendsModel = new ListDataModel(friends);
}
public void addAsFriend() {
Friend selectedFriend = (Friend) friendsModel.getRowData();
// ...
}
}
with
<h:dataTable value="#{bean.friendsModel}" var="friend">
<h:column>
<h:commandButton value="Add as friend" action="#{bean.addAsFriend}" />
</h:column>
</h:dataTable>
Should work as good with IBM Faces Client Framework (those hx: components).

Resources