Objeto selecionado em DataTable estava sendo enviado para o servidor como null


O problema que eu estava enfrentando era que quando eu tentava no botão de “deletar” (como mostra na imagem acima), o valor de selectedUserPermission era definido para o objeto referente a linha na qual eu clicava, devido a seguinte configuração do componente setPropertyActionListener que adiciona o objeto userPermission na propriedade selectedUserPermission no servidor.

<p:commandButton class="ui-button-warning rounded-button" icon="pi pi-trash"
				 process="@this dt-permission"
				 oncomplete="PF('deletePermissionDialog').show()">
	<f:setPropertyActionListener value="#{userPermission}"
								 target="#{permissionController.selectedUserPermission}"/>
</p:commandButton>

Note

Além disso é necessário adicionar os seguintes atributos no componente Data Table do Primefaces:

rowKey="#{userPermission.fiscalCode}"
selection="#{permissionController.selectedUserPermission}"

O valor de rowKey deve ser uma String para o Primefaces poder recuperar o objeto da linha selecionada em selection.

Porém ao confirmar a exclusão do registro, clicando em “Sim”, como mostra o dialog abaixo:

O JSF definia o campo selectedUserPermission para null no servidor (antes estava com o valor correto).

Código do dialog:

<p:confirmDialog widgetVar="deletePermissionDialog"
				 showEffect="fade" width="300"
				 message="Excluir as permissões deste usuário?"
				 header="Confirmar"
				 severity="warn"
>
	<p:commandButton value="Sim" icon="pi pi-check"
					 actionListener="#{permissionController.deletePermission()}"
					 oncomplete="PF('deletePermissionDialog').hide()"/>
 
	<p:commandButton value="Não" type="button"
					 styleClass="ui-button-secondary" icon="pi pi-times"
					 onclick="PF('deletePermissionDialog').hide()"/>
 
</p:confirmDialog>

Como solução foi a adição do atributo process="@this" no componente commandButton de confirmação da exclusão, pois dessa forma na requisição AJAX feito pelo botão para o servidor é enviado apenas o estado e a ação do botão. Sem esse atributo, por padrão é enviado todo o estado dos campos presentes na página, incluindo o estado de selectedUserPermission que estava null uma vez que as informações da Data Table são resetadas assim que um nova view é renderizada (no caso o Dialog).

Solução:

@Controller
@Scope("session")
@Data
public class PermissionController {
 
	private ArrayList<CompanyPermissionResponse> permissions;
    private CompanyPermissionResponse selectedUserPermission;
 
	// ...
 
	public void deletePermission() {
		try {
			microserviceCompanyPermission
				.deletePermission(
					currentCompany.getIdCompany(),
					selectedUserPermission.getIdUser()
				);
 
            FacesContext
	            .getCurrentInstance()
	            .addMessage(
		            null, 
		            new FacesMessage(
			            FacesMessage.SEVERITY_INFO, 
			            "Sucesso.", ""
					)
				);
        } catch (Exception e) {
            FacesContext
	            .getCurrentInstance()
	            .addMessage(
		            null,
		            new FacesMessage(
			            FacesMessage.SEVERITY_ERROR,
			            "Erro", e.getMessage()
					)
				);
        } finally {
            resetFieldsState();
        }
    }
}

Página XHTML:

<p:dataTable id="dt-permission" widgetVar="dtUsers"
			 var="userPermission"
			 value="#{permissionController.permissions}"
			 reflow="true"
			 rowKey="#{userPermission.fiscalCode}"
			 selection="#{permissionController.selectedUserPermission}"
			 paginator="true" rows="10" paginatorPosition="bottom">
 
	<!-- Outros campos -->
 
	<p:column exportable="false">
 
		<!-- Outras ações -->
 
		<p:commandButton class="ui-button-warning rounded-button" icon="pi pi-trash"
						 process="@this dt-permission"
						 oncomplete="PF('deletePermissionDialog').show()">
			<f:setPropertyActionListener value="#{userPermission}"
										 target="#{permissionController.selectedUserPermission}"/>
		</p:commandButton>
 
	</p:column>
</p:dataTable>
 
<!-- Delete Dialog -->
<p:confirmDialog widgetVar="deletePermissionDialog" showEffect="fade" width="300"
				 message="Excluir as permissões deste usuário?" header="Confirmar" severity="warn">
	<p:commandButton value="Sim" icon="pi pi-check"
					 process="@this"
					 actionListener="#{permissionController.deletePermission()}"
					 oncomplete="PF('deletePermissionDialog').hide()"/>
 
	<p:commandButton value="Não" type="button"
					 styleClass="ui-button-secondary" icon="pi pi-times"
					 onclick="PF('deletePermissionDialog').hide()"/>
</p:confirmDialog>

Referências