ПРИМЕЧАНИЕ: Этот вопрос был сильно отредактирован, так как был найден наработанный пример. Однако проблема остается практически такой же, как и , как представляется, надуманный пример работает.includeViewParams = true не работает в комбинации с композитным компонентом, который выполняет итерацию по коллекции
Рассмотрим следующую JSF страницы:
<!DOCTYPE html>
<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:ui="http://java.sun.com/jsf/facelets">
<f:view contentType="text/html">
<h:head>
<title>Page</title>
</h:head>
<h:body>
<ui:composition template="/WEB-INF/templates/myLayout.xhtml">
<ui:define name="metadata">
<f:metadata>
<f:viewParam name="foobar" value="#{pageBean.foo}"/>
</f:metadata>
</ui:define>
<ui:define name="content">
<h:form>
<h:commandLink value="Click"
action="#{util.currentPageAction()}"/>
</h:form>
</ui:define>
</ui:composition>
</h:body>
</f:view>
</html>
И эти бобы:
@Named
@RequestScoped
public class PageBean implements Serializable
{
public String getFoo()
{
return foo;
}
public void setFoo(String foo)
{
this.foo = foo;
}
private String foo;
}
@Named
@ApplicationScoped
public class Util implements Serializable
{
public String currentPageAction()
{
return FacesContext.getCurrentInstance().getViewRoot().getViewId() +
"?faces-redirect=true&includeViewParams=true";
}
}
Это надуманный пример на самом деле, как и ожидалось, - в частности, она проходит через исходные значения из просматривать параметры URL-адреса при перенаправлении. Так, например, если исходный URL-адрес равен http://localhost:8080/faces/pages/test.xhtml?foo=bar
, когда я нажимаю на <h:commandLink/>
, полный URL-адрес, включая параметры представления, выдержит перенаправление.
Проблема в том, что, когда я перехожу от этого надуманного примера к чему-то более реальному (в моем случае, странице поиска), параметры вида не пережить перенаправление.
Вот настоящая страница, для которой она не работает. Извините, это немного длинно для типичного вопроса stackoverflow.
<!DOCTYPE html>
<html xmlns="http://www.w3.org/1999/xhtml"
xmlns:h="http://java.sun.com/jsf/html"
xmlns:ui="http://java.sun.com/jsf/facelets"
xmlns:f="http://java.sun.com/jsf/core"
xmlns:p="http://primefaces.org/ui"
xmlns:search="http://java.sun.com/jsf/composite/components/search"
xmlns:oc="http://java.sun.com/jsf/composite/components/mysite"
xmlns:fn="http://www.mysite.com.au/jsf">
<h:head>
<title></title>
</h:head>
<h:body>
<ui:composition template="/WEB-INF/templates/myLayout.xhtml">
<ui:define name="metadata">
<f:metadata>
<f:viewParam name="address" value="#{searchBean.address}"/>
<f:viewParam name="lng" value="#{searchBean.longitude}" required="#{!facesContext.postback}" requiredMessage="Longitude is required" validatorMessage="Longitude is invalid">
<f:validateDoubleRange minimum="-180" maximum="180"/>
</f:viewParam>
<f:viewParam name="lat" value="#{searchBean.latitude}" required="#{!facesContext.postback}" requiredMessage="Latitude is required" validatorMessage="Latitude is invalid">
<f:validateDoubleRange minimum="-90" maximum="90"/>
</f:viewParam>
<f:viewParam name="gender" value="#{searchBean.gender}"/>
<f:viewParam name="language" value="#{searchBean.spokenLanguageId}"/>
<f:viewParam name="service" value="#{searchBean.serviceId}"/>
<f:viewParam name="rangeKm" value="#{searchBean.rangeKm}" validatorMessage="Range (km) is invalid">
<f:validateLongRange minimum="1"/>
</f:viewParam>
<f:viewParam name="weeksOffset" value="#{searchBean.weeksOffset}"/>
<f:event type="preRenderView" listener="#{searchBean.preRender(e)}"/>
</f:metadata>
</ui:define>
<ui:define name="windowTitle">#{searchBean.address}</ui:define>
<ui:define name="scripts">
<script type="text/javascript">
var mysite = mysite || {};
mysite.longitude = #{searchBean.longitude};
mysite.latitude = #{searchBean.latitude};
mysite.defaultAddress = "#{applicationBean.defaultAddress}";
mysite.region = "#{applicationBean.region}";
mysite.baseUrl = "#{applicationBean.baseUrl}";
</script>
<h:outputScript library="javascript" name="map2.js"/>
<h:outputScript name="geocode.js" library="javascript" target="head"/>
<h:outputScript name="search.js" library="javascript" target="head"/>
</ui:define>
<ui:define name="rightSidebar">
<div class="ocSearch_sidebarSection">
<oc:map styleClass="search"/>
<div>
<a style="font-size:11px;text-decoration:underline;" href="#" onclick="mysite.resetMap();return false;">Reset</a>
</div>
</div>
<oc:context-menu-container isFirstChild="false">
<oc:context-menu title="Search Options">
<form id="searchForm" method="get" onsubmit="return mysite.geocode(this);">
<div style="clear:both;float:left;">
<label for="ocSearchRadius">Service Providers within</label>
<div id="ocSearchRadius">
<input type="text" id="ocRangeKm" name="rangeKm" value="#{searchBean.rangeKm}" style="width:20px;float:left;"/>
<div style="width:40px;margin-top:5px;float:left;overflow:hidden;text-align:center;vertical-align:bottom;">km of</div>
<input type="text" id="ocAddress" name="address" value="#{searchBean.address}" style="width:104px;float:left;"/>
</div>
</div>
<div style="float:left;">
<div style="width:60px;margin-right:10px;float:left;">
<label for="ocGender" style="display:block;">Gender</label>
<select id="ocGender" name="gender" style="width:50px;">
<h:panelGroup rendered="#{searchBean.gender eq 'any'}">
<option value="any" selected="selected">Any</option>
<option value="female">Female</option>
<option value="male">Male</option>
</h:panelGroup>
<h:panelGroup rendered="#{searchBean.gender eq 'female'}">
<option value="any">Any</option>
<option value="female" selected="selected">Female</option>
<option value="male">Male</option>
</h:panelGroup>
<h:panelGroup rendered="#{searchBean.gender eq 'male'}">
<option value="any">Any</option>
<option value="female">Female</option>
<option value="male" selected="selected">Male</option>
</h:panelGroup>
</select>
</div>
<div style="float:left;">
<label for="ocLanguage">Language</label>
<select id="ocLanguage" name="language" style="width:176px;">
<ui:repeat value="#{commonRequestBean.spokenLanguageItems}" var="item">
<h:panelGroup rendered="#{searchBean.spokenLanguageId eq item.value}">
<option value="#{item.value}" selected="yes">#{item.label}</option>
</h:panelGroup>
<h:panelGroup rendered="#{searchBean.spokenLanguageId ne item.value}">
<option value="#{item.value}">#{item.label}</option>
</h:panelGroup>
</ui:repeat>
</select>
</div>
</div>
<div style="float:left;">
<label for="ocService">Reason for visit</label>
<select id="ocService" name="service" style="width:176px;" >
<ui:repeat value="#{commonRequestBean.serviceItems}" var="item">
<h:panelGroup rendered="#{searchBean.serviceId eq item.value}">
<option value="#{item.value}" selected="yes">#{item.label}</option>
</h:panelGroup>
<h:panelGroup rendered="#{searchBean.serviceId ne item.value}">
<option value="#{item.value}">#{item.label}</option>
</h:panelGroup>
</ui:repeat>
</select>
</div>
<div style="float:left;">
<label for="ocStartDate">From</label>
<select id="ocStartDate" name="weeksOffset" style="width:176px;">
<ui:repeat value="#{fn:selectableDates(13)}" var="date" varStatus="dateStatus">
<h:panelGroup rendered="#{date.value eq searchBean.weeksOffset}">
<option value="#{date.value}" selected="yes">#{date.label}</option>
</h:panelGroup>
<h:panelGroup rendered="#{date.value ne searchBean.weeksOffset}">
<option value="#{date.value}">#{date.label}</option>
</h:panelGroup>
</ui:repeat>
</select>
</div>
<div style="margin-top:8px;float:left;">
<p:button id="searchAgainButton" value="Search Again"/>
<script type="text/javascript">
//<![CDATA[
$(function(){
// Replace the Search Again button with a clone whose type is submit.
var oldButton = $('#searchAgainButton');
var newButton = oldButton.clone(true);
newButton.attr("type","submit");
newButton.attr("id","searchAgainButtonClone");
newButton.removeAttr("onclick");
newButton.insertBefore(oldButton);
oldButton.remove();
newButton.attr("id","searchAgainButton");
});
//]]>
</script>
</div>
<input type="hidden" id="ocLng" name="lng" value="#{searchBean.longitude}"/>
<input type="hidden" id="ocLat" name="lat" value="#{searchBean.latitude}"/>
</form>
<script>
// Ensure the form fields are set to the current values. (Webkit bug workaround.)
$(function(){
$('#ocRangeKm').val('#{searchBean.rangeKm}');
$('#ocAddress').val('#{searchBean.address}');
$('#ocGender').val('#{searchBean.gender}');
$('#ocLanguage').val('#{searchBean.spokenLanguageId}');
$('#ocService').val('#{searchBean.serviceId}');
$('#ocStartDate').val('#{searchBean.weeksOffset}');
});
</script>
</oc:context-menu>
</oc:context-menu-container>
</ui:define>
<ui:define name="content">
<div id="ocSearchResultsHeader" class="fixed">
<div style="margin-left:10px;">
<h3 style="margin:8px 0 4px 0;">#{searchBean.searchResultsTitle}</h3>
<span class="help">Click a time to book #{searchBean.service.indefiniteArticle} #{searchBean.service.name}</span>
</div>
</div>
<div class="ocSearch_resultSet">
<h:form>
<h:commandLink value="Foobar" action="#{util.currentPageAction}"/>
</h:form>
<search:result resultSet="#{searchBean.results}" startDate="#{searchBean.startDate}"/>
</div>
</ui:define>
</ui:composition>
</h:body>
</html>
Основополагающий фасоли, searchBean
, является запросом областью действия так же, как надуманный пример.
Обновление: Если я удалю экземпляр составного компонента <search:result/>
, он теперь работает. Это совершенно неожиданно. Аналогично, если я оставлю экземпляр компонента там и вырезаю тело самого компонента, он работает. Таким образом, в компоненте есть что-то, что мешает чему-то другому. Weird. Я посмотрю, смогу ли я понять, что это такое.
Обновление: Это похоже на ошибку. Если я заменю композитный компонент на это:
<ui:repeat value="#{searchBean.results} var="item" varStatus="itemStatus">
<h:outputText value="#{item.mapMarker}"/>
<br/>
</ui:repeat>
он также терпит неудачу, как и для композитного компонента.
Точно так же это не удается:
<h:dataTable value="#{searchBean.results}" var="item">
<h:column>
<h:outputText value="#{item.mapMarker}"/>
<br/>
</h:column>
</h:dataTable>
В моем конкретном случае, есть три результата, так что я могу перебрать их вручную, как например:
<ui:param name="results" value="#{searchBean.results}"/>
<br/>
<h:outputText value="#{results.get(0).mapMarker}"/>
<br/>
<h:outputText value="#{results.get(1).mapMarker}"/>
<br/>
<h:outputText value="#{results.get(2).mapMarker}"/>
<br/>
и она работает.
Так что есть что-то об итерации по результатам, которые завинчиваются с помощью <h:commandLink/>
.
Что может произойти неправильно? Еще одна ошибка Mojarra, где простой случай использования терпит неудачу?
Окончательное обновление: Сузили проблему с надуманными примерами и переместили вопрос here.
Извините @BalusC - Я вижу, что вы удалили свой ответ. У меня проблема была прибита - см. Ссылку в «Окончательное обновление». –
Я удалил его, потому что он не ответил на ваш вопрос :) Не стесняйтесь удалять текущий вопрос, а также он слишком широк. Ваш новый вопрос намного лучше. – BalusC
Мой новый вопрос * слегка * неправильный. Но это делает его еще проще. Исправлена. –