我没有关于如何解决这个问题的想法,这就是发生的事情:当我点击一个应该更新我的视图的按钮(通过ajax)时,服务器端代码被正确执行,但是视图没有更新。当我发出第二个ajax请求时,它会使用最后一个ajax请求的值进行更新。它发生在我的页面中的每个ajax操作,这意味着视图上的所有内容始终显示旧数据。几岁? 1请求旧,总是。
深入研究这个问题我找到了一些可能的原因,为此,在下一行中,我将更详细地解释我想要做什么。
我有一个事件列表,每个事件都发生在一个日期。我的页面显示12个日历,每月一个,这些日历的目标是显示每月每天发生的事件。除了日历,我还有一个改变年份的面板和一个对话框。每次用户单击日历中的日期时,都会打开该对话框。通过对话,您可以添加新活动,删除点击的活动并编辑点击的活动。
每个日历都是我自定义组件的一个实例"日历"它总是收到一个月,一年和一系列事件作为参数。事件列表通过方法" getEvents(int month)"在我的managedBean中。
我的ajax电话是:
正如我之前所说,一切都正确完成,但更新。由ajax请求触发的更新刚刚在下一个ajax请求中完成。
为了调查发生了什么,我将printlns放入方法" getEvents(int month)"知道什么时候被召唤以及它发现了什么事件。
令我惊讶的是,每个ajaxCall都会调用getEvents,如果ajax调用更新了日历,则无关紧要。总是,在执行服务器端方法之前,会为12个日历调用getEvents。
我的结论是:更新发生在ajax请求完成之前。确认我在ajax方法中写了一些printlns(和flushs)。在任何ajax方法完成之前,都会调用getEvents。我认为当JSF调用update时,它使用方法执行之前获得的值,而不是新的值,是什么导致视图总是一个请求迟到。
有人见过这样的问题吗?提前感谢您的帮助。
编辑:代码很复杂。为了简化问题,我将问题减少到了改变年份"需求。如果我删除其他所有内容,问题仍然存在。
我的观点:
<h:outputStylesheet library="components" name="calendar/aqua/calendar.css" />
<link href="css/event_calendar.css" rel="stylesheet" type="text/css" />
<f:metadata>
<f:viewParam name="year" value="#{managementEventCalendar.year}" />
<f:event type="preRenderView" listener="#{managementEventCalendar.preRender()}" />
</f:metadata>
<script type="text/javascript">
<!-- update the url parameter "year" according to the managed bean -->
$(document).ready(function(){
updateUrlParameter('year', #{managementEventCalendar.year});
});
</script>
<p:growl autoUpdate="true" showDetail="true" life="#{initParam['primefaces.growl.life']}" widgetVar="growlWidgetVar" />
<!-- just a title, irrelevant -->
<comp:management_title image="imgs/title_image_eventcalendar.png" title="#{msg['title.eventcalendar']}" description="#{msg['description.eventcalendar']}" styleClass="event" />
<!-- form to change the year -->
<h:form>
<p class="text-center year-block">
<p:commandButton icon="ui-icon-circle-arrow-w" actionListener="#{managementEventCalendar.previousYear()}" update="@form :calendar" oncomplete="updateUrlParameter('year', #{managementEventCalendar.year - 1});" />
<h:outputText styleClass="year-title" value="#{managementEventCalendar.year}" />
<p:commandButton icon="ui-icon-circle-arrow-e" actionListener="#{managementEventCalendar.nextYear()}" update="@form :calendar" oncomplete="updateUrlParameter('year', #{managementEventCalendar.year + 1});" />
</p>
</h:form>
<!-- Grid of calendars (12, one for each month) -->
<h:panelGrid id="calendar" columns="3" width="100%" cellpadding="0" cellspacing="0" style="margin-bottom: 15px"
columnClasses="calendar-column left, calendar-column center, calendar-column right">
<comp:calendar month="0" year="#{managementEventCalendar.year}" disablePast="false" theme="aqua"
type="edition" eventDates="#{managementEventCalendar.getEvents(0)}" />
<comp:calendar month="1" year="#{managementEventCalendar.year}" disablePast="false" theme="aqua"
type="edition" eventDates="#{managementEventCalendar.getEvents(1)}" />
<comp:calendar month="2" year="#{managementEventCalendar.year}" disablePast="false" theme="aqua"
type="edition" eventDates="#{managementEventCalendar.getEvents(2)}" />
<comp:calendar month="3" year="#{managementEventCalendar.year}" styleClass="espacamento_vertical" disablePast="false" theme="aqua"
type="edition" eventDates="#{managementEventCalendar.getEvents(3)}" />
<comp:calendar month="4" year="#{managementEventCalendar.year}" styleClass="espacamento_vertical" disablePast="false" theme="aqua"
type="edition" eventDates="#{managementEventCalendar.getEvents(4)}" />
<comp:calendar month="5" year="#{managementEventCalendar.year}" styleClass="espacamento_vertical" disablePast="false" theme="aqua"
type="edition" eventDates="#{managementEventCalendar.getEvents(5)}" />
<comp:calendar month="6" year="#{managementEventCalendar.year}" styleClass="espacamento_vertical" disablePast="false" theme="aqua"
type="edition" eventDates="#{managementEventCalendar.getEvents(6)}" />
<comp:calendar month="7" year="#{managementEventCalendar.year}" styleClass="espacamento_vertical" disablePast="false" theme="aqua"
type="edition" eventDates="#{managementEventCalendar.getEvents(7)}" />
<comp:calendar month="8" year="#{managementEventCalendar.year}" styleClass="espacamento_vertical" disablePast="false" theme="aqua"
type="edition" eventDates="#{managementEventCalendar.getEvents(8)}" />
<comp:calendar month="9" year="#{managementEventCalendar.year}" styleClass="espacamento_vertical" disablePast="false" theme="aqua"
type="edition" eventDates="#{managementEventCalendar.getEvents(9)}" />
<comp:calendar month="10" year="#{managementEventCalendar.year}" styleClass="espacamento_vertical" disablePast="false" theme="aqua"
type="edition" eventDates="#{managementEventCalendar.getEvents(10)}" />
<comp:calendar month="11" year="#{managementEventCalendar.year}" styleClass="espacamento_vertical" disablePast="false" theme="aqua"
type="edition" eventDates="#{managementEventCalendar.getEvents(11)}" />
</h:panelGrid>
关于组件&#34;日历&#34;:disablePast和主题的一些解释是装饰性的。 &#34; type = edition&#34;表示日历单元格可以选择。选择如何运作是不相关的,因为我们只考虑我们想要改变年份的情况。我删除了有关事件选择,编辑和取消的所有代码。所有问题都存在。
请参阅下面的组件代码&#34; calendar&#34;。
<composite:interface componentType="calendar">
<composite:attribute name="month" type="java.lang.Integer" required="true" />
<composite:attribute name="year" type="java.lang.Integer" required="true" />
<composite:attribute name="eventDates" type="java.util.List" required="false" />
<composite:attribute name="style" required="false" />
<composite:attribute name="styleClass" required="false" />
<composite:attribute name="disablePast" required="false" default="true" />
<composite:attribute name="theme" required="false" default="rose" />
<composite:attribute name="type" required="false" default="tooltip" />
<composite:attribute name="eventManager" type="com.ae.client.web.management.EventManager" required="false" />
<composite:attribute name="onselect" required="false" />
<composite:attribute name="update" required="false" />
</composite:interface>
<composite:implementation>
<h:outputScript library="components" name="calendar/calendar.js" target="head" />
<c:set var="disabled" value="#{cc.attrs.disablePast and cc.isPastMonth()}" />
<div class="calendar-component">
<table cellspacing="0" cellpadding="0" border="0" width="254px" style="#{cc.attrs.style}"
class="calendar-table month_#{cc.attrs.month} #{disabled ? 'disabled' : ''} #{cc.attrs.type} #{cc.attrs.styleClass}">
<!-- Month name and week days -->
<tr>
<th rowspan="#{cc.numberOfWeeks + 1}" class="month">
<h:graphicImage library="components" alt="#{cc.getMonthName()}"
name="calendar/#{cc.attrs.theme}/#{msg.locale}/month_#{disabled ? 'disabled_' : ''}#{cc.attrs.month}.png" />
</th>
<th class="week">D</th>
<th class="week">S</th>
<th class="week">T</th>
<th class="week">Q</th>
<th class="week">Q</th>
<th class="week">S</th>
<th class="week">S</th>
</tr>
<!-- Month days -->
<ui:repeat value="#{cc.calendar}" var="week">
<tr>
<ui:repeat value="#{week}" var="day">
<td class="#{(day.isToday() ? 'today' : '')} #{(empty (day.events)) ? '' : 'event'} #{(day.dayOfMonth eq 0) ? '' : 'selectable'}">
<h:panelGroup layout="block" styleClass="relative" rendered="#{not (day.dayOfMonth eq 0)}">
<h:outputText class="day-of-month" value="#{day.dayOfMonth}" />
<!-- events in the day -->
<ui:repeat value="#{day.events}" var="eventDate">
<div class="event-data">
<h:outputText class="id" value="#{eventDate.event.id}" />
<span class="name">
<h:outputText value="#{eventDate.event.name}" />
<h:outputText value=" - #{eventDate.description}" rendered="#{not empty(eventDate.description) and eventDate.event.eventDates.size() gt 1}" />
</span>
<h:outputText class="status" value="#{eventDate.event.status}" />
<h:outputText class="time" value="#{eventDate.date}">
<f:convertDateTime timeZone="#{msg['date.timezone']}" pattern="#{msg['time.format']}" type="time" />
</h:outputText>
</div>
</ui:repeat>
</h:panelGroup>
</td>
</ui:repeat>
</tr>
</ui:repeat>
</table>
</div>
</composite:implementation>
我的托管bean代码很简单,我分析了url参数&#34; year&#34;在预渲染事件中,并在首次调用getEvents(int month)时填充我的事件集合。事件集合实际上是将月份(0-11)与事件日期列表(EventDate)相关联的映射。事件可以在多个日期(eventDates)中发生,每个eventDate都有一个日期和一个简短的描述。要转到前一年,我调用方法previousYear()。请参阅下面的一些managedBean代码:
public void preRender(){
GregorianCalendar today = new GregorianCalendar();
if (year == 0) year = today.get(GregorianCalendar.YEAR);
}
@Override
public void updateEventCollection() {
eventMap = new HashMap<Integer, List<EventDate>>();
Iterator<Event> eventIterator = eventRepository.findNotCanceledByYear(year).iterator();
while (eventIterator.hasNext()){
Event e = eventIterator.next();
Iterator<EventDate> dateIterator = e.getEventDates().iterator();
while (dateIterator.hasNext()){
EventDate date = dateIterator.next();
GregorianCalendar day = new GregorianCalendar();
day.setTime(date.getDate());
int month = day.get(GregorianCalendar.MONTH);
List<EventDate> eventsInMonth = eventMap.get(month);
if (null == eventsInMonth){
eventsInMonth = new ArrayList<EventDate>();
}
eventsInMonth.add(date);
eventMap.put(month, eventsInMonth);
}
}
}
public List<EventDate> getEvents(int month){
if (null == eventMap) updateEventCollection();
List<EventDate> result = eventMap.get(month);
if (null == result) result = new ArrayList<EventDate>();
System.out.println("*** getting events of month " + month + ". " + result.size() + " dates were found.");
System.out.flush();
return result;
}
public void nextYear(){
year++;
updateEventCollection();
}
public void previousYear(){
year--;
updateEventCollection();
}
我希望它有所帮助。
描述我的问题,特别是在&#34;更改年份&#34;要求:如果页面是在2013年加载的,我单击按钮&#34;上一个&#34;,表示年份的文本正确更新到2013,日历似乎也会更新,但具有我以前的相同值(2013年),它根本没有更新。当我再次点击时,年份文本更新为2011,但日历显示为2012.如果我再次单击,则日历将始终显示上一个请求的结果。
编辑:经过一番挖掘后,似乎问题在于利用,我不知道为什么会导致这样的问题,但是当我删除组件代码的以下部分时,每个变量都成功更新到视图中。
<!-- Month days -->
<ui:repeat value="#{cc.calendar}" var="week">
<tr>
<ui:repeat value="#{week}" var="day">
<td class="#{(day.isToday() ? 'today' : '')} #{(empty (day.events)) ? '' : 'event'} #{(day.dayOfMonth eq 0) ? '' : 'selectable'}">
<h:panelGroup layout="block" styleClass="relative" rendered="#{not (day.dayOfMonth eq 0)}">
<h:outputText class="day-of-month" value="#{day.dayOfMonth}" />
</h:panelGroup>
</td>
</ui:repeat>
</tr>
</ui:repeat>
如果我删除第二个ui:重复问题仍在继续,如果我删除这两个问题就会消失,是什么让我觉得它与迭代结果有关&#34; cc.calendar&#34;。变量cc.calendar没有特别的问题,因为为了进行测试,在删除之后,我在视图中打印以下内容:
<h:outputText value="#{cc.attrs.year}" /><br />
<h:outputText value="#{cc.calendar.size()}" /><br />
<h:outputText value="#{cc.attrs.eventDates.size()}" /><br />
cc.calendar.size()的值表明所有内容都在正确的时间内正确更新。如果我让这些&#34;打印&#34;在代码中并恢复ui:重复,打印的值是错误的,只要我发出另一个ajax请求就会更新,总是一个请求迟到。
似乎问题完全是ui:repeat标签,我不知道如何修复它。我试过c:forEach,同样的问题。