[英]Refreshing a table containing panels correctly in wicket
I have a wicket panel that contains a table. 我有一个包含一张桌子的检票盘。 This is its constructor:
这是它的构造函数:
public NotFinishedExamsPanel(String id, final String userId, String[] egal) {
super(id, new ResourceModel("notFinishedExams"), true);
this.setOutputMarkupId(true);
MySystem mysystem = ((MySession) Session.get()).getMySystem();
String uid = ((MySession) Session.get()).getUsername();
ArrayList<ExamData> exams = new ArrayList<ExamData>();
try {
if (!mysystem.account(userId).isStudent()) {
return;
}
for (String exId : mysystem.exams()) {
Exam ex = mysystem.exam(exId);
if ((!(ex.hasResult(mysystem.account(userId).student().id()) && (ex.isPublished())))) {
exams.add(new ExamData(mysystem.account(userId).student().id(), exId));
}
}
ExamProvider exProv = new ExamProvider(exams);
ArrayList<IColumn<ExamData, String>> columns = new ArrayList<IColumn<ExamData, String>>();
columns.add(new PropertyColumn<ExamData, String>(new ResourceModel("title", "Titel"), "title"));
columns.add(new PropertyColumn<ExamData, String>(new ResourceModel("date", "Datum"), "date"));
columns.add(new PropertyColumn<ExamData, String>(new ResourceModel("time", "Uhrzeit"), "time"));
columns.add(new PropertyColumn<ExamData, String>(new ResourceModel("location", "Ort"), "location"));
columns.add(new PropertyColumn<ExamData, String>(new ResourceModel("status", "Status"), "status") {
private static final long serialVersionUID = 7758862055950720446L;
public void populateItem(Item item, String componentId, IModel rowModel) {
Status status = ((ExamData) rowModel.getObject()).status;
item.add(new ShowExamStatusPanel(componentId, status));
}
});
columns.add(new PropertyColumn<ExamData, String>(new Model<String>(""), "status") {
private static final long serialVersionUID = 7758862055950720446L;
public void populateItem(Item item, String componentId, IModel rowModel) {
String examId = ((ExamData) rowModel.getObject()).examId;
String studentId = ((ExamData) rowModel.getObject()).studentId;
Status status = ((ExamData) rowModel.getObject()).status;
item.add(new ChangeExamStatusPanel(componentId, userId, examId, studentId, status));
}
});
DefaultDataTable<ExamData, String> ddt = new DefaultDataTable<ExamData, String>("datatable", columns, exProv, 64);
collapsible.add(ddt);
} catch (NoSuchElementException e) {
error(e.getMessage());
}
}
collapsible is a WebMarkupContainer (div tag) inherited from the superclass (the superclass extends Panel). collapsible是一个继承自超类的WebMarkupContainer(div标签)(超类扩展了Panel)。 As you can see, in the last two columns I don't just put in a simple text, but a special panel.
正如您所看到的,在最后两列中,我不只是放入一个简单的文本,而是一个特殊的面板。
ShowExamStatusPanel contains a label showing whether you are signed in for this exam or not: ShowExamStatusPanel包含一个标签,显示您是否已登录此考试:
class ShowExamStatusPanel extends Panel {
private static final long serialVersionUID = 6359496765268390462L;
public ShowExamStatusPanel(String id, final Status status) {
super(id);
this.setOutputMarkupId(true);
Label showStatus = new Label("showStatus", new AbstractReadOnlyModel<String>() {
private static final long serialVersionUID = 1L;
public String getObject() {
return ((status == Status.SIGNED_IN || status == Status.SIGNED_IN_CLOSED) ? (new ResourceModel("signed_in").getObject()) : (new ResourceModel("not_signed_in")).getObject());
}
});
showStatus.add(new AttributeModifier("class", ((status == Status.SIGNED_IN || status == Status.SIGNED_IN_CLOSED) ? "examSignedUpColor" : "examNotSignedUpColor")));
this.add(showStatus);
}
}
ChangeExamStatusPanel contains a link that toggles your state for the exam (it signs in if you aren't and signs off otherwise): ChangeExamStatusPanel包含一个切换您的考试状态的链接(如果您不是,则签名,否则签名):
class ChangeExamStatusPanel extends Panel {
private static final long serialVersionUID = -8527825882073976118L;
public ChangeExamStatusPanel(final String id, final String userId, final String examId, final String studentId, final Status status) {
super(id);
this.setOutputMarkupId(true);
MySystem mysystem = ((MySession) Session.get()).getMySystem();
AjaxLink cesl= new AjaxLink("changeExamStatusLink") {
private static final long serialVersionUID = 4306084754982648221L;
@Override
public void onClick(AjaxRequestTarget target) {
MySystem mysystem = ((MySession) Session.get()).getMySystem();
try {
if (status == Status.SIGNED_IN) {
mysystem.exam(examId).removeParticipant(userId, studentId);
} else if (status == Status.NOT_SIGNED_IN) {
mysystem.exam(examId).addParticipant(userId, studentId);
}
} catch (Exception e) {
NotFinishedExamsPanel.this.error(e.getMessage());
}
target.addChildren(NotFinishedExamsPanel.this, ChangeExamStatusPanel.class);
target.addChildren(NotFinishedExamsPanel.this, ShowExamStatusPanel.class);
target.add(NotFinishedExamsPanel.this);
}
};
Label ceslText = new Label("linkText", ("[" + (new ResourceModel((status == Status.SIGNED_IN || status == Status.SIGNED_IN_CLOSED) ? "sign_off" : "sign_in")).getObject() + "]"));
cesl.add(ceslText);
ceslText.setVisibilityAllowed(status == Status.SIGNED_IN || status == Status.NOT_SIGNED_IN);
this.add(cesl);
}
}
When the link is clicked, I want the table to be refreshed because the signed-in-state for one exam has changed. 单击链接后,我希望刷新表,因为一个考试的签名状态已更改。 But I don't get this working.
但我没有这个工作。 With the code above, nothing happens when I click on the link.
使用上面的代码,当我点击链接时没有任何反应。 If I then press F5 and refresh the whole page, I see the changes.
如果我然后按F5并刷新整个页面,我会看到更改。
What do I have to do to refresh only the table (including inner panels)? 如何仅刷新表格(包括内部面板),我该怎么办?
Here the html files, if you need them: 这里是html文件,如果你需要它们:
NotFinishedExamsPanel.html: NotFinishedExamsPanel.html:
<html xmlns:wicket="http://wicket.apache.org/dtds.data/wicket-xhtml1.4-strict.dtd">
<head>
</head>
<body>
<wicket:extend>
<table wicket:id="datatable" class="datatable" style="margin:0px"></table>
</wicket:extend>
</body>
</html>
NotFinishedExamsPanel$ShowExamStatusPanel.html: NotFinishedExamsPanel $ ShowExamStatusPanel.html:
<html xmlns:wicket="http://wicket.apache.org/dtds.data/wicket-xhtml1.4-strict.dtd">
<wicket:panel>
<span wicket:id="showStatus"></span>
</wicket:panel>
</html>
NotFinishedExamsPanel$ChangeExamStatusPanel.html: NotFinishedExamsPanel $ ChangeExamStatusPanel.html:
<html xmlns:wicket="http://wicket.apache.org/dtds.data/wicket-xhtml1.4-strict.dtd">
<wicket:panel>
<a wicket:id="changeExamStatusLink" href="#"><span wicket:id="linkText"></span></a>
</wicket:panel>
</html>
ExamProvider.java: ExamProvider.java:
class ExamProvider extends SortableDataProvider<ExamData, String> {
private static final long serialVersionUID = 1476722834865141105L;
private ExamDataProviderComparator comparator = new ExamDataProviderComparator();
private List<ExamData> examList;
public ExamProvider(List<ExamData> examList) {
this.examList = examList;
this.setSort("date", SortOrder.DESCENDING);
}
public Iterator<ExamData> iterator(long first, long count) {
List<ExamData> newList = new ArrayList<ExamData>(this.examList);
Collections.sort(newList, comparator);
return newList.subList((int) first, (int) (first + count)).iterator();
}
public long size() {
return this.examList.size();
}
public IModel<ExamData> model(final ExamData object) {
return new AbstractReadOnlyModel<ExamData>() {
private static final long serialVersionUID = -3048436145666499501L;
public ExamData getObject() {
return (ExamData) object;
}
};
}
class ExamDataProviderComparator implements Comparator<ExamData>, Serializable {
private static final long serialVersionUID = 7660088204512731476L;
public int compare(final ExamData o1, final ExamData o2) {
PropertyModel<Comparable> model1 = new PropertyModel<Comparable>(o1, getSort().getProperty());
PropertyModel<Comparable> model2 = new PropertyModel<Comparable>(o2, getSort().getProperty());
int result = 0;
if (model1.getObject() instanceof String && model2.getObject() instanceof String) {
if (getSort().getProperty().equalsIgnoreCase("date")) {
try {
SimpleDateFormat sdt = new SimpleDateFormat("dd.MM.yyyy", Locale.GERMAN);
Date d1 = sdt.parse(model1.getObject().toString());
Date d2 = sdt.parse(model2.getObject().toString());
result = d1.compareTo(d2);
} catch (ParseException e) {
result = Collator.getInstance(Locale.GERMAN).compare(model1.getObject(), model2.getObject());
}
} else {
result = Collator.getInstance(Locale.GERMAN).compare(model1.getObject(), model2.getObject());
}
} else {
result = model1.getObject().compareTo(model2.getObject());
}
if (!getSort().isAscending()) {
result = -result;
}
return result;
}
}
}
Wicket calls the constructor (Page or components) only when the page is constructed . Wicket仅在构造页面时调用构造函数(页面或组件)。 So after adding the
NotFinishedExamsPanel
to AjaxRequestTarget
, Wicket is refreshing the table based on the data in ArrayList<ExamData> exams
(which is still the same). 因此,在将
NotFinishedExamsPanel
添加到AjaxRequestTarget
,Wicket会根据ArrayList<ExamData> exams
的数据刷新表(这仍然是相同的)。
I would propose you the following approach to impelemnt the ExamProvider
(I was not able to test the code so take that only as a suggestion): 我建议你使用以下方法来
ExamProvider
(我无法测试代码,所以只能作为建议):
static class ExamProvider extends SortableDataProvider<ExamData, String> {
private static final long serialVersionUID = 1L;
private static final String DEFAULT_SORT = "foobar";
private IModel<List<ExamData>> examsModel = new ExamDataLoader();
@Override
public Iterator<ExamData> iterator(long first, long count) {
SortParam<String> sort = getSort();
List<ExamData> examDataList = examsModel.getObject();
// TODO sort
String orderByColumn = sort != null ? DEFAULT_SORT : sort.getProperty();
boolean desc = sort != null ? true : !sort.isAscending();
return examDataList.iterator();
}
@Override
public long size() {
return examsModel.getObject().size();
};
@Override
public IModel<ExamData> model(ExamData data) {
final String examId = data.getExamId();
return new LoadableDetachableModel<ExamData>() {
@Override
protected ExamData load() {
MySystem mysystem = MySession.get().getMySystem();
final long userId = mysystem.account(userId).student().id();
Exam ex = mysystem.exam(examId);
return new ExamData(mysystem.account(userId).student().id(), examId);
}
};
}
@Override
public void detach() {
examsModel.detach();
super.detach();
}
}
With: 附:
static class ExamDataLoader extends LoadableDetachableModel<List<ExamData>> {
private static final long serialVersionUID = 1L;
@Override
protected List<ExamData> load() {
MySystem mysystem = MySession.get().getMySystem();
long userId = mysystem.account(userId).student().id();
List<String> examsIds = mysystem.exams();
List<ExamData> exams = new ArrayList<>(examsIds.size());
for (String exId : mysystem.exams()) {
Exam ex = mysystem.exam(exId);
if ((!(ex.hasResult(userId) && (ex.isPublished())))) {
exams.add(new ExamData(mysystem.account(userId).student().id(), exId));
}
}
return exams;
}
}
To make your life a little bit easier, hide the static method get()
in MySession
with: 为了让您的生活更轻松,请在
MySession
隐藏静态方法get()
:
public static MySession get() {
return (MySession) Session.get();
}
One last thing: Never change the visibility (or other attributes of a component) in the constructor (same argument as for your initial problem). 最后一件事:永远不要改变构造函数中的可见性(或组件的其他属性)(与初始问题相同的参数)。 So instead of:
所以代替:
if (!mysystem.account(userId).isStudent()) { return; }
overwrite the onConfigure
method ad set the visibility based on given restrictions. 覆盖
onConfigure
方法广告根据给定的限制设置可见性。
声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.