我有一个显示视图的重复控件。我现在想要包含一个复选框,以便我可以对所选文档执行操作。添加复选框没有问题,但是如何检查复选框是否已选中,然后转到该行的相关文档?
我的想法是:
复选框更改事件是否从数组范围变量中添加或删除文档的UNID。然后只对该数组中的文档执行操作。
忘记复选框,只需弹出一个列表框,允许用户从中进行选择。
但有更简单的方法吗?
答案 0 :(得分:9)
为了获得最大的灵活性,最好不要将我们的用户界面组件直接绑定到数据;相反,如果我们引入一个中间的“数据模型”层(通常是描述数据代表的真实世界对象/人/过程的层,而不是在“文档”中思考,这最终只是证明这些真实的 - 世界存在的东西),我们的UI代码变得非常干净,易于理解,易于维护。当我们继续在文档中思考时,它还可以更容易地引入令人沮丧的功能。
例如,假设我们使用Extension Library中的对象数据源创建一个任意对象(例如,我们称之为pendingRequests
),我们以后可以将我们的重复控制绑定到(而不是直接将其绑定到视图):
// Create an empty array to return at the end:
var results = [];
// Create a view navigator instance for iterating the view contents:
var pendingView = database.getView("pendingRequests");
var entryNavigator = pendingView.createViewNav();
var eachEntry = entryNavigator.getFirst();
while (eachEntry != null) {
// Add metadata about each entry to result array:
var metaData = eachEntry.getColumnValues();
results.push({
startDate: metaData.get(0).getDateOnly(),
endDate: metaData.get(1).getDateOnly(),
employeeName: metaData.get(2),
status: metaData.get(3),
unid: eachEntry.getUniversalID(),
selected: "0"
});
// In case any column values were Domino objects:
recycleAll(metaData);
// Cruise on to the next:
eachEntry = navigateToNext(entryNavigator, eachEntry);
}
// Final Domino handle cleanup:
recycleAll(entryNavigator, pendingView);
// Return our now populated array:
return results;
在继续之前,我应该指出,上面的示例包括两个非平台原生的语法糖果:recycleAll()
和navigateToNext()
。这两个都只是实用功能,使愚蠢的recycle
东西更容易处理:
<强> recycleAll 强>
* More convenient recycling
*/
function recycleAll() {
for(var i = 0; i < arguments.length; i++) {
var eachObject = arguments[i];
// assume this is a collection
try {
var iterator = eachObject.iterator();
while (iterator.hasNext()) {
recycleAll(iterator.next());
}
} catch (collectionException) {
try {
eachObject.recycle();
} catch (recycleException) {
}
}
}
}
<强> navigateToNext 强>
/*
* Safe way to navigate view entries
*/
function navigateToNext(navigator, currentEntry) {
var nextEntry = null;
try {
nextEntry = navigator.getNext(currentEntry);
} catch (e) {
} finally {
recycleAll(currentEntry);
}
return nextEntry;
}
好的,现在回到数据模型......具体来说,这个块:
var metaData = eachEntry.getColumnValues();
results.push({
startDate: metaData.get(0).getDateOnly(),
endDate: metaData.get(1).getDateOnly(),
employeeName: metaData.get(2),
status: metaData.get(3),
unid: eachEntry.getUniversalID(),
selected: "0"
});
因此,对于每个视图条目,我们创建一个非常简单的对象,其中包含我们希望允许用户与之交互的所有相关信息,以及为我们自己的代码提供方便的两个额外属性:{{1}如果我们需要,它允许返回到文档,unid
,它为我们提供了一种方法,可以将复选框绑定到此元数据对象的属性...这意味着用户可以通过以下方式切换其值复选框。
所以这是我们如何向用户表示这些数据的基本示例:
selected
重复控件中的每个复选框现在直接绑定到元数据对象的<ul style="list-style-type: none;">
<xp:repeat var="vacationRequest" value="#{pendingRequests}">
<li style="margin-bottom:10px;">
<strong>
<xp:checkBox value="#{vacationRequest.selected}" text="#{vacationRequest.startDate} - #{vacationRequest.endDate}"
checkedValue="1" uncheckedValue="0" />
</strong>
<xp:text value="#{vacationRequest.employeeName} (#{vacationRequest.status})" tagName="div" />
</li>
</xp:repeat>
</ul>
属性,每个“行”代表...也具有selected
属性,因此根据实际文档进行操作与此数据模型相对应的很简单:
unid
由于我们的数据源只是这些元数据对象的数组,我们可以循环遍历每个元数据对象,询问用户是否已切换每个元素的for (var i = 0; i < pendingRequests.length; i++) {
var eachRequest = pendingRequests[i];
if (eachRequest.selected == "1") {
var requestDataSource = database.getDocumentByUNID(eachRequest.unid);
requestDataSource.replaceItemValue("status", "Approved");
if (requestDataSource.save()) {
// update in-memory metadata:
eachRequest.status = "Approved";
}
}
}
属性,如果是,则获取其对应的句柄文档,修改一个或多个项目,并保存。 注意:因为我们在此示例中使用了数据源,所以不会在每个事件上重新加载后端视图数据。出于性能原因,这是一个非常好的事情(tm)。但它确实意味着我们必须更新内存中的元数据对象以匹配我们在文档上更改的内容(即selected
)...但这也意味着我们只能更新 而不是必须废弃我们的整个数据源,并让它从视图中读回所有内容。
作为奖励,添加类似“全选”按钮的内容更简单:
eachRequest.status = "Approved"
因此,总而言之,我们有一个内存数据模型,在许多情况下,等效操作将更快地执行,但也允许我们编写更少的代码 - 更可读的代码 - 来做更好的事情。
如果你想现场玩这个模式(和/或在上下文中下载所有上述源代码),我已经永久化它here。
答案 1 :(得分:2)
布鲁斯, 我从重复控件中选择了一个视频。我没有使用复选框,但使用了“添加”和“删除”按钮,然后执行了一些CSS来突出显示所选文档。我确定一个复选框可以使用与添加/删除按钮基本相同的代码。
基本上我在内存中创建了一个java.util.ArrayList来保存unids,然后在单击重复行时填充该数组。我为每一行计算了CSS,如果该数组中存在UNID,我会更改背景颜色以显示它的“已选择”。我实际上并没有在选定的unids上显示任何处理,但由于该数组位于作用域内存中,因此您几乎可以使用它进行任何操作。无论如何,视频演示在这里:
http://notesin9.com/index.php/2011/04/01/notesin9-025-selecting-documents-from-a-repeat-control/
答案 2 :(得分:2)
一如既往,Tim的回答是您长期健康,理智和代码可维护性的最佳选择。
在我开始使用Java进行所有后端逻辑之前,我还有另一条路线。您可以创建一个包含HashMap的页面加载绑定dataContext,然后将每个复选框绑定到它 - 它将为每个键填充true或false,这样您就可以循环遍历映射条目并找到那些是真的,是检查值。
我整理了一个快速示例,从名称数据库中提取列表以显示我的意思:
<?xml version="1.0" encoding="UTF-8"?>
<xp:view xmlns:xp="http://www.ibm.com/xsp/core">
<xp:this.data>
<xp:dominoView var="names" databaseName="names.nsf" viewName="$NamesFieldLookup"/>
</xp:this.data>
<xp:this.dataContexts>
<xp:dataContext var="checkedNames" value="${javascript: new java.util.HashMap() }"/>
</xp:this.dataContexts>
<xp:div id="refresher">
<xp:repeat value="#{names}" var="name" rows="3">
<xp:this.facets>
<xp:pager xp:key="header" id="pager1" layout="Previous Group Next" />
</xp:this.facets>
<div>
<xp:checkBox value="#{checkedNames[name.$9]}">
<xp:eventHandler event="onclick" submit="true" refreshMode="partial" refreshId="refresher"/>
</xp:checkBox>
<xp:text value="#{name.$9}"/>
</div>
</xp:repeat>
<p><xp:text value="#{checkedNames}"/></p>
</xp:div>
</xp:view>