Xpages是在视图中循环并进行更改的最佳方式
这个问题快把我逼疯了 我可以查看带有类别的文档。现在文档的顺序是任意的,但是我想为用户提供一种简单的方法来上下移动类别中的文档。因此,视图中有上/下箭头 我在箭头后面有SSJS代码,可以更改文档中的“订单”值,以便它们可以向上或向下移动(在我的pick中,任务字段显示订单) 我的问题是它间歇性地工作。我想原因是因为我在循环中时,文档的顺序正在改变。我尝试将视图上的自动更新设置设置为手动,但它似乎仍然不起作用 也许我是在走这条路去硬的。我真的只需要更改两个文档,一个是用户选择的文档,另一个是他们将其移动到的文档。仅仅抓住这些可能会更简单吗Xpages是在视图中循环并进行更改的最佳方式,xpages,Xpages,这个问题快把我逼疯了 我可以查看带有类别的文档。现在文档的顺序是任意的,但是我想为用户提供一种简单的方法来上下移动类别中的文档。因此,视图中有上/下箭头 我在箭头后面有SSJS代码,可以更改文档中的“订单”值,以便它们可以向上或向下移动(在我的pick中,任务字段显示订单) 我的问题是它间歇性地工作。我想原因是因为我在循环中时,文档的顺序正在改变。我尝试将视图上的自动更新设置设置为手动,但它似乎仍然不起作用 也许我是在走这条路去硬的。我真的只需要更改两个文档,一个是用户选择的文档,另一个是他们
function mveItm(mveDir,mveCat,curOrd) {
var curOrdStr:String = String(curOrd);
var tarOrd:Integer;
var tarOrdStr:String;
var doc:NotesDocument;
var lstOrd:Integer;
var fstOrd:Integer;
//Grab Collection In Order
var tskView = database.getView("(dbAllPCTasksAutoUpdateFalse)");
tskView.refresh();
tskView.setAutoUpdate(false);
var veCol:NotesViewEntryCollection = tskView.getAllEntriesByKey(mveCat);
//Set First and Last Order Number
var fstOrd = 10
var lstOrd = veCol.getCount() * 10;
//If the user has clicked move Higher on the last item
//or move down on the first, then ignore
if (mveDir == "Lower" && fstOrd == curOrd)
{return}
if (mveDir == "Higher" && lstOrd == curOrd)
{return}
//Move Higher
if (mveDir == "Higher") {
//Set target order
tarOrd = curOrd + 10;
tarOrdStr = String(tarOrd);
//Loop through viewEntryCollection and process
var entry:NotesViewEntry = veCol.getFirstEntry();
while (entry != null) {
doc = entry.getDocument()
//Where are we in the loop
var n:String = String(entry.getDocument().getItemValueInteger("order"));
//If the number we are on matches the number that was selected to be changed
//Change the current number to the target number
if (n == curOrdStr)
{
print ("We are in order");
print ("This is the one we are on..." + n);
print ("This is the one we passed in..." + String(curOrdStr));
print ("This is the target..." + String(tarOrd));
doc.replaceItemValue("order",tarOrd);
doc.save;
}
//If the number we are on matches the number that was the target
//Change the number we are on to the selected order number
if (n == tarOrdStr)
{
doc.replaceItemValue("order",curOrd);
doc.save;
}
var tmpentry:NotesViewEntry = veCol.getNextEntry(entry);
entry.recycle();
entry = tmpentry;
}
}
//Move down
if (mveDir == "Lower") {
//Set target order
tarOrd = curOrd - 10;
tarOrdStr = String(tarOrd);
//Loop through viewEntryCollection and add to DocumentCollection
var entry:NotesViewEntry = veCol.getFirstEntry();
while (entry != null) {
doc = entry.getDocument()
//Where are we in the loop
var n:String = String(entry.getDocument().getItemValueInteger("order"));
//If the number we are on matches the number that was selected to be changed
//Change the current number to the target number
if (n == curOrdStr)
{
//doc = entry.getDocument()
doc.replaceItemValue("order",tarOrd);
doc.save;
}
//If the number we are on matches the number that was the target
//Change the number we are on to the selected order number
if (n == tarOrdStr)
//Change the current number to the target number and change everyone after that to -10
//if (movDwn == true)
{
doc.replaceItemValue("order",curOrd);
doc.save;
}
var tmpentry:NotesViewEntry = veCol.getNextEntry(entry);
entry.recycle();
entry = tmpentry;
}
}
tskView.setAutoUpdate(true);
tskView.refresh();
//resetCategories(mveCat);
return true;
}
我在这里发布我的完整解决方案。代码在最后,我将解释我做了什么来解决这个问题。感谢大卫和克努特·赫尔曼对我的帮助——请看克努特的帖子
我的问题如下:用户可以输入带有类别的文档(我的示例是“OS”和“软件”)。我希望用户可以通过重复控件中的箭头轻松地对其进行排序。他们还必须能够选择要删除的多个文档,并添加文档,并且顺序始终正确。为了更难,我为该类别设置了一个过滤器,以便用户可以看到所有类别或一个类别(该解决方案也适用于多个类别)
订单的实际更改并不太困难。我意识到我不必检查一个类别中的所有文档,只需获取用户选择的文档,以及下一个更高或下一个更低的文档(取决于他们想做什么),并交换位置。这一部分并不太难(参见库中的方法mveTsk)
困难的部分是确定是否显示向上或向下移动箭头。如果项目是第一个项目,则无法显示向下箭头;如果项目是最后一个项目,则无法显示向上箭头。此外,如果用户删除了一个项目或两个或三个项目,则必须对项目重新排序
我认为这是一个很好的解决方案,应该适用于许多不同的情况
============================
完整代码:
[无法输入所有代码]这是我认为最重要的
<?xml version="1.0" encoding="UTF-8"?>
<xp:view
xmlns:xp="http://www.ibm.com/xsp/core"
xmlns:xe="http://www.ibm.com/xsp/coreex"
xmlns:xc="http://www.ibm.com/xsp/custom"
style="font-size:8pt">
<xp:this.data>
<xp:dominoView
var="view1"
viewName="(xpAllPCBuilds)" />
</xp:this.data>
<xp:this.resources>
<xp:styleSheet
href="/custom.css" />
</xp:this.resources>
<xp:this.beforePageLoad><![CDATA[#{javascript:viewScope.put("rows","5")}]]></xp:this.beforePageLoad>
<xe:widgetContainer id="widgetContainerView" style="width:99.00%">
<xp:panel>
<xp:repeat
id="repeat1"
var="rowData"
indexVar="repeatIndex"
value="#{view1}"
>
<xp:this.facets>
<xp:text
disableTheme="true"
xp:key="header"
escape="false">
<xp:this.value><![CDATA[<table class='lotusTable repeatRowColors' border='0' cellspacing='0' cellpadding='0'>
<tr class ='lotusFirst lotusSort scope='col'>
<th></th>
<th class ='lotusBold'>Employee Name</th>
<th class ='lotusBold'>Computer</th>
<th class ='lotusBold'>Create Date</th>
<th class ='lotusBold'>Create User</th>
<th class ='lotusBold'>ID</th>
</tr>
</thead>]]>
</xp:this.value>
<xp:panel id="pagerPnlTop">
<xp:table
styleClass="lotusPaging lotusPagingTop"
style="width:100%">
<xp:tr>
<xp:td styleClass="lotusLeft">
<xp:panel
themeId="Panel.left"
styleClass="xspRowCount">
 
 
 
 
 
 
 
 
 
</xp:panel>
</xp:td>
<xp:td styleClass="lotusRight">
</xp:td>
</xp:tr>
</xp:table>
</xp:panel>
</xp:text>
<xp:text
disableTheme="true"
xp:key="footer"
escape="false"
>
<xp:this.value>
<![CDATA[</table>]]></xp:this.value>
<xp:panel id="pagerPnlBottom">
<xp:table
styleClass="lotusPaging lotusPagingTop"
style="width:100%"
>
<xp:tr>
<xp:td styleClass="lotusLeft">
<xp:panel
themeId="Panel.left"
styleClass="xspRowCount"
>
<xp:label
value="Show: "
id="label1"
/>
<xp:link
text="5"
id="link2"
>
<xp:this.style>
<![CDATA[#{javascript:if (viewScope.get("rows") == 5)
{return "color:#808080;font-weight:normal;"}
else
{return "font-weight:bold"}}]]>
</xp:this.style>
<xp:eventHandler
event="onclick"
submit="true"
refreshMode="complete"
>
<xp:this.action>
<![CDATA[#{javascript:var numEntries = 5;
viewScope.rows = numEntries;
var dt = getComponent("repeat1");
if(dt != null && dt.getRowCount() > 0) {
dt.setFirst(0);
}}]]>
</xp:this.action>
</xp:eventHandler>
</xp:link>
 
<xp:label
value="|"
id="label2"
themeId="Text.smallSeparator"
/>
 
<xp:link
text="10"
id="link3"
>
<xp:this.style>
<![CDATA[#{javascript:if (viewScope.get("rows") == 10)
{return "color:#808080;font-weight:normal;"}
else
{return "font-weight:bold"}}]]>
</xp:this.style>
<xp:eventHandler
event="onclick"
submit="true"
refreshMode="complete"
>
<xp:this.action>
<![CDATA[#{javascript:var numEntries = 10;
viewScope.rows = numEntries;
var dt = getComponent("repeat1");
if(dt != null && dt.getRowCount() > 0) {
dt.setFirst(0);
}}]]>
</xp:this.action>
</xp:eventHandler>
</xp:link>
 
<xp:label
value="|"
id="label3"
themeId="Text.smallSeparator"
/>
 
<xp:link
text="25"
id="link4"
>
<xp:this.style>
<![CDATA[#{javascript:if (viewScope.get("rows") == 25)
{return "color:#808080;font-weight:normal;"}
else
{return "font-weight:bold"}}]]>
</xp:this.style>
<xp:eventHandler
event="onclick"
submit="true"
refreshMode="complete"
>
<xp:this.action>
<![CDATA[#{javascript:var numEntries = 25;
viewScope.rows = numEntries;
var dt = getComponent("repeat1");
if(dt != null && dt.getRowCount() > 0) {
dt.setFirst(0);
}}]]>
</xp:this.action>
</xp:eventHandler>
</xp:link>
 
<xp:label
value="|"
id="label4"
themeId="Text.smallSeparator"
/>
 
<xp:link
text="50"
id="link6"
>
<xp:this.style>
<![CDATA[#{javascript:if (viewScope.get("rows") == 50)
{return "color:#808080;font-weight:normal;"}
else
{return "font-weight:bold"}}]]>
</xp:this.style>
<xp:eventHandler
event="onclick"
submit="true"
refreshMode="complete"
>
<xp:this.action>
<![CDATA[#{javascript:var numEntries = 50;
viewScope.rows = numEntries;
var dt = getComponent("repeat1");
if(dt != null && dt.getRowCount() > 0) {
dt.setFirst(0);
}}]]>
</xp:this.action>
</xp:eventHandler>
</xp:link>
 
<xp:label
value="|"
id="label5"
themeId="Text.smallSeparator"
/>
 
<xp:link
text="100"
id="link7"
>
<xp:this.style>
<![CDATA[#{javascript:if (viewScope.get("rows") == 100)
{return "color:#808080;font-weight:normal;"}
else
{return "font-weight:bold"}}]]>
</xp:this.style>
<xp:eventHandler
event="onclick"
submit="true"
refreshMode="complete"
>
<xp:this.action>
<![CDATA[#{javascript:var numEntries = 100;
viewScope.rows = numEntries;
var dt = getComponent("repeat1");
if(dt != null && dt.getRowCount() > 0) {
dt.setFirst(0);
}}]]>
</xp:this.action>
</xp:eventHandler>
</xp:link>
 
<xp:label
value=" entries"
id="label6"
/>
</xp:panel>
</xp:td>
<xp:td styleClass="lotusRight">
<xp:pager
xp:key="headerPager"
layout="Previous Group Next"
for="repeat1"
id="pager5"
style="font-weight:inherit"
styleClass="pagerTopRight"
/>
</xp:td>
</xp:tr>
</xp:table>
</xp:panel>
</xp:text>
</xp:this.facets>
<xp:this.rows><![CDATA[#{javascript:var rows:Integere = viewScope.get("rows");
if (rows == null)
{return 5}
else
{return rows}}]]></xp:this.rows>
<xp:tr id="rowDataContainer">
<xp:td
style="width:20px;min-width:20px;max-width: 20px;"
>
<xc:ccRowSelectCheckBox
docID="#{javascript:rowData.getNoteID()}"
selectedClass="selectedRow"
containerID="rowDataContainer"
/>
</xp:td>
<xp:td
style="width:200px;min-width:200px;max-width: 200px;"
>
<xp:link
escape="true"
id="link1"
value=""
>
<xp:this.text><![CDATA[#{javascript:rowData.getColumnValue("employeeName")}]]></xp:this.text>
<xp:eventHandler
event="onclick"
submit="true"
refreshMode="complete"
>
<xp:this.action>
<xp:openPage
name="xpFormPCBuild.xsp"
target="openDocument"
>
<xp:this.documentId><![CDATA[#{javascript:rowData.getDocument().getUniversalID()}]]></xp:this.documentId>
</xp:openPage>
</xp:this.action>
</xp:eventHandler>
</xp:link>
</xp:td>
<xp:td
style="width:75px;min-width:75px;max-width:75px;">
<xp:text
escape="true"
id="computedField2">
<xp:this.value><![CDATA[#{javascript:rowData.getColumnValue("computerName");}]]>
</xp:this.value>
</xp:text>
</xp:td>
<xp:td
style="width:100px;min-width:100px;max-width:100px;">
<xp:text
escape="true"
id="computedField3">
<xp:this.value><![CDATA[#{javascript:rowData.getColumnValue("CrtDte");}]]>
</xp:this.value>
</xp:text>
</xp:td>
<xp:td
style="width:150px;min-width:150px;max-width: 150px;">
<xp:text
escape="true"
id="computedField4">
<xp:this.value><![CDATA[#{javascript:rowData.getColumnValue("crtUsr");}]]>
</xp:this.value>
</xp:text>
</xp:td>
<xp:td>
<xp:text
escape="true"
id="computedField5">
<xp:this.value><![CDATA[#{javascript:rowData.getColumnValue("ID")}]]></xp:this.value>
</xp:text>
</xp:td>
</xp:tr>
</xp:repeat>
</xp:panel>
</xe:widgetContainer>
</xp:view>
嗯,我认为有几种方法可以做到这一点。我没有确切的答案,但如果时间允许,我有兴趣进一步探索。 你不会说有多少文档或者排序顺序是什么。但是如果文档包含排序顺序的字段,那么你就可以很容易地进行操作,只需进行视图刷新。不过我假设这不是一个选项。 我相信java.util.ArrayList会控制插入对象的顺序。如果不是,那么可能是LinkedList。无论如何,如果你创建了一个列表,然后在视图中循环添加文档unid到列表中。那么理论上你就有了一个按视图顺序排列的unid列表。NotesViewNavigator和NotesViewEntry应该可以很快做到这一点。现在你可以我将其转换为一个repeat控件,从UNID获取文档,然后再获取您想要的任何其他值。 那么你会如何影响顺序呢?如果单元的列表在范围内,或者你只需要一个Java方法来“上移”或“下移”。我看到这个问题,它看起来像是一个Collections.swap方法。即使这不是答案,也一定有一些很酷的Java解决方案。 无论如何,这不是一个明确的答案,但也许有一些想法让你去追求
(请确保在获得最终解决方案后发布。)您必须拥有SSJS解决方案还是基于Java的解决方案?我没有说我有什么,但我只是想知道。此外,我不明白为什么您要调用tskView.refresh()就在您获得视图之后。我看不出性能受到影响有任何意义…Java就可以了。至于刷新,只是为了确保在我的测试中刷新它。我会在生产中关闭它。我现在想知道如果根本不做循环是否会简单得多。用户正在移动当前文档(他们点击箭头的那个)向上或向下。抓取当前文档,然后抓取上一个文档或下一个文档,这取决于他们选择的是向下箭头还是向上箭头。只需交换两个文档的顺序并保存。也许这就是解决方法?Dave我仍在研究我的解决方案,完成后会发布,或者如果无法解决问题,会与您联系,但我想我也是这样戴夫,我找到了一个我认为非常好的解决方案,并把它贴在上面。
var validateForm = function()
{
var valid = true;
var control;
var control2;
var val;
var val2;
REMOVED business code
function mveTsk(mveDir,pckCat,pckOrd) {
//OK I am assuming we are only moving something that we can move
//Set variables
var pckDoc:NotesDocument;
var trgDoc:NotesDocument;
var trgOrd:Integer;
var tskView = database.getView("(dbAllPCTasksLookup)");
var key:String = createKey(pckCat,pckOrd);
//Get the chosen doc
var query = key;
var pckDoc = tskView.getDocumentByKey(query);
//Get the current order
var curOrd:Integer = pckDoc.getItemValueInteger("order");
//Get doc depending on whether we are moving higher or lower
if (mveDir == "Lower")
{query = createKey(pckCat,pckOrd-1);
var trgDoc = tskView.getDocumentByKey(query);
pckDoc.replaceItemValue("order",curOrd-1)
pckDoc.replaceItemValue("key",createKey(pckCat,curOrd-1))
trgOrd = trgDoc.getItemValueInteger("order");
trgOrd += 1;
trgDoc.replaceItemValue("order",trgOrd)
trgDoc.replaceItemValue("key",createKey(pckCat,trgOrd))}
else
{query = createKey(pckCat,pckOrd+1);
print (query);
var trgDoc = tskView.getDocumentByKey(query);
pckDoc.replaceItemValue("order",curOrd+1)
pckDoc.replaceItemValue("key",createKey(pckCat,curOrd+1))
trgOrd = trgDoc.getItemValueInteger("order");
trgOrd -= 1;
trgDoc.replaceItemValue("order",trgOrd)
trgDoc.replaceItemValue("key",createKey(pckCat,trgOrd))}
pckDoc.save();
trgDoc.save();
resetCategories(pckCat);
return
}
function resetCategories (rstCat)
{
var tskView = database.getView("(dbAllPCTasks)");
var veCol:NotesViewEntryCollection = tskView.getAllEntriesByKey(rstCat);
var veCnt = veCol.getCount();
var curCnt:Integer;
var tmpDoc:NotesDocument;
var curOrd:Integer;
var chgOrd:Integer = 0;
var doc:NotesDocument
print (String(veCnt));
//We have no records so get out
if (veCnt == 0) {
return;
}
//We have one record, so set this record and get out
if (veCnt == 1) {
var entry:NotesViewEntry = veCol.getFirstEntry();
doc = entry.getDocument()
doc.replaceItemValue("order",1);
doc.replaceItemValue("key",createKey(rstCat,1));
doc.save();
return;
}
//We have one first and one last record, so set these two records and get out
if (veCnt == 2) {
//First Entry
var entry:NotesViewEntry = veCol.getFirstEntry();
doc = entry.getDocument()
doc.replaceItemValue("order",1);
doc.replaceItemValue("key",createKey(rstCat,1));
doc.save();
//Second Entry
var entry:NotesViewEntry = veCol.getNextEntry(entry);
doc = entry.getDocument()
doc.replaceItemValue("order",2);
doc.replaceItemValue("key",createKey(rstCat,2));
doc.save();
return;
}
//Else we have 3 or more so go through the loop
print ("we have more");
curCnt = 1
var entry:NotesViewEntry = veCol.getFirstEntry();
while (entry != null) {
doc = entry.getDocument()
print (String(curCnt));
//We are the first record
if (curCnt == 1) {
doc.replaceItemValue("order",curCnt);
doc.replaceItemValue("key",createKey(rstCat,curCnt));
doc.save();
}
//We are the last record
if (curCnt == veCnt) {
doc.replaceItemValue("order",curCnt);
doc.replaceItemValue("key",createKey(rstCat,curCnt));
doc.save();
}
//We are neither first nor last; inbetween record
if ( (curCnt != 1) && (curCnt != veCnt)) {
doc.replaceItemValue("order",curCnt);
doc.replaceItemValue("key",createKey(rstCat,curCnt));
doc.save();
}
var tmpentry:NotesViewEntry = veCol.getNextEntry(entry);
entry.recycle();
entry = tmpentry;
curCnt = curCnt + 1
}
return
}
function orderToString (tmpOrd)
{
keyString:String
tmpOrdStr:String = tmpOrd
if (len(tmpOrdStr == 1))
{keyString = "00" + tmpOrdStr;}
if (len(tmpOrdStr == 2))
{keyString = "0" + tmpOrdStr;}
if (len(tmpOrdStr == 3))
{keyString = tmpOrdStr;}
return keyString
}