JSTL c: forEach no funciona dentro de un JSF h: dataTable
(2)
Intenta usar ui: repite tag en lugar de c: forEach. Lee este enlace para saber por qué ui: repite el uso en lugar de c: forEach.
Tengo un problema con un proyecto JSF.
- GlassFish Server 3.1.2
- Mojarra 2.1.6
Estoy tratando de mostrar una tabla que contiene los campos de encabezado de solicitud. Por lo tanto, he escrito este bean administrado:
import java.util.Collections;
import java.util.LinkedHashMap;
import java.util.List;
import javax.annotation.PostConstruct;
import javax.faces.bean.ManagedBean;
import javax.faces.bean.RequestScoped;
import javax.faces.context.FacesContext;
import javax.servlet.http.HttpServletRequest;
@ManagedBean
@RequestScoped
public class RequestHeader extends LinkedHashMap<String, List<String>> {
private List<String> keys;
@PostConstruct
public void init() {
final HttpServletRequest request = (HttpServletRequest) FacesContext.getCurrentInstance().getExternalContext().getRequest();
keys = Collections.list(request.getHeaderNames());
for (final String key : keys) {
final List<String> value = Collections.list(request.getHeaders(key));
final List<String> oldValue = get(key);
if (oldValue == null) {
put(key, value);
} else {
oldValue.addAll(value);
}
}
}
public List<String> keys() {
return keys;
}
}
Esta es mi página JSF:
<?xml version=''1.0'' encoding=''UTF-8'' ?>
<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd">
<html xmlns="http://www.w3.org/1999/xhtml"
xmlns:h="http://java.sun.com/jsf/html"
xmlns:f="http://java.sun.com/jsf/core"
xmlns:c="http://java.sun.com/jsp/jstl/core">
<h:head>
<title>HTTP request headers</title>
</h:head>
<h:body>
<h:dataTable value="#{requestHeader.keys()}" var="k" border="1">
<f:facet name="header">HTTP request headers</f:facet>
<h:column>
<f:facet name="header">Key</f:facet>
<h:outputText value="#{k}" />
</h:column>
<h:column>
<f:facet name="header">Value</f:facet>
<!-- This forEach seems to be ignored. -->
<c:forEach items="#{requestHeader[k]}" var="v">
<h:outputText value="#{v}" /><br />
</c:forEach>
</h:column>
</h:dataTable>
</h:body>
</html>
En lugar de tener los valores en la segunda columna de la tabla, las celdas están vacías:
<?xml version=''1.0'' encoding=''UTF-8'' ?>
<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd">
<html xmlns="http://www.w3.org/1999/xhtml">
<head>
<title>HTTP request headers</title>
</head>
<body>
<table border="1">
<thead>
<tr><th colspan="2" scope="colgroup">HTTP request headers</th></tr>
<tr>
<th scope="col">Key</th>
<th scope="col">Value</th>
</tr>
</thead>
<tbody>
<tr>
<td>user-agent</td>
<td></td>
</tr>
<tr>
<td>host</td>
<td></td>
</tr>
<tr>
<td>accept</td>
<td></td>
</tr>
<tr>
<td>accept-language</td>
<td></td>
</tr>
<tr>
<td>accept-encoding</td>
<td></td>
</tr>
<tr>
<td>cache-control</td>
<td></td>
</tr>
<tr>
<td>connection</td>
<td></td>
</tr>
</tbody>
</table>
</body>
</html>
Hice varias pruebas. <h:outputText value="#{requestHeader[k]}" />
c:forEach
en otras listas funcionará.
¿Por qué no funciona de esta manera?
Los manejadores de etiquetas como las etiquetas JSTL se ejecutan durante el tiempo de compilación de la vista, mientras que los componentes de la IU como las etiquetas JSF <h:xxx>
ejecutan durante el tiempo de visualización de la vista. Por lo tanto, no se ejecutan sincronizados como cabría esperar de la codificación. En su código, en el momento en que se ejecuta <c:forEach>
, <h:dataTable>
no se ha ejecutado y, por lo tanto, su atributo var
no se ha establecido y, por lo tanto, #{k}
no está disponible cuando <c:forEach>
runs y, por lo tanto, recupera una colección vacía / inexistente.
En su lugar, necesita un componente UI si desea una iteración anidada dentro de otro componente UI. Uno de ellos es Facelets <ui:repeat>
.
<ui:repeat value="#{requestHeader[k]}" var="v">
<h:outputText value="#{v}" /><br />
</ui:repeat>
En caso de que todavía esté en JSF 1.x, use Tomahawk''s <t:dataList>
lugar, o simplemente otra <h:dataTable>
.
Ver también:
No relacionado con el problema concreto: no necesitas un respaldo de grano aquí en absoluto. Todos los encabezados de solicitud ya están disponibles como un Map
por el objeto EL implícito #{header}
.
Con todo, su enfoque se puede simplificar de la siguiente manera, sin ningún respaldo bean:
<h:dataTable value="#{header.keySet().toArray()}" var="headerName" border="1">
<f:facet name="header">HTTP request headers</f:facet>
<h:column>
<f:facet name="header">Name</f:facet>
<h:outputText value="#{headerName}" />
</h:column>
<h:column>
<f:facet name="header">Value</f:facet>
<ui:repeat value="#{header[headerName]}" var="headerValue">
<h:outputText value="#{headerValue}" /><br />
</ui:repeat>
</h:column>
</h:dataTable>