Xpages 遍历视图并进行更改的最佳方式

Xpages best way to loop through view and make changes

这个问题快把我逼疯了。

我可以查看带类别的文档。现在文档的顺序是任意的,但我想为用户提供一种简单的方法来向上或向下移动类别中的文档。所以我在视图中有 up/down 个箭头。

我在箭头后面有 SSJS 代码,它更改了文档中的 "order" 值,因此它们会向上或向下移动(在我的选择中,任务字段显示顺序)。

我的问题是它时断时续地工作。我认为原因是因为当我在循环中时文档的顺序正在改变。我尝试将视图上的自动更新设置设置为手动,但它似乎仍然不起作用。

也许我走这条路太难了。我真的只需要更改 2 个文档,一个是用户选择的,另一个是他们要将其移动到的文档。只是抓住那些可能会更简单吗?

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;
}

我正在post这里使用我的完整解决方案。代码在最后,我会解释我做了什么来解决这个问题。感谢 David 和 Knut Hermann 为我提供的帮助 - 请在此处查看 Knut 的 post。

我的问题如下:用户可以输入带有类别的文档(我的示例是 "OS" 和 "Software"。我希望用户可以通过重复的箭头轻松地对它们进行排序控制。他们还必须能够 select 删除和添加多个文档,顺序将始终正确。只是为了更难,我为类别添加了一个过滤器,这样用户可能会看到所有类别或一个类别(此解决方案也适用于多个类别)。

实际改单并不太难。我意识到我不必浏览一个类别中的所有文档,只需获取用户 select 编辑的文档,然后是下一个更高的或下一个更低的,这取决于他们想做什么,然后交换位置.那部分并不太难(参见库中的方法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">


                                            &#160;

                                            &#160;

                                            &#160;

                                            &#160;

                                            &#160;

                                            &#160;

                                            &#160;

                                            &#160;

                                            &#160;

                                        </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>
                                            &#160;
                                            <xp:label
                                                value="|"
                                                id="label2"
                                                themeId="Text.smallSeparator"
                                            />
                                            &#160;
                                            <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>
                                            &#160;
                                            <xp:label
                                                value="|"
                                                id="label3"
                                                themeId="Text.smallSeparator"
                                            />
                                            &#160;
                                            <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>
                                            &#160;
                                            <xp:label
                                                value="|"
                                                id="label4"
                                                themeId="Text.smallSeparator"
                                            />
                                            &#160;
                                            <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>
                                            &#160;
                                            <xp:label
                                                value="|"
                                                id="label5"
                                                themeId="Text.smallSeparator"
                                            />
                                            &#160;
                                            <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>
                                            &#160;
                                            <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>

SSJS 库

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
    }

好吧,我认为有几种方法可以做到这一点。我没有确切的答案,但如果时间允许,我有兴趣进一步探索它。 您没有说有多少文档或排序顺序是什么。但是,如果文档包含排序顺序的字段,那么我认为您可以很容易地对其进行操作,只需刷新视图即可。我会假设这不是一个选择。 我相信 java.util.ArrayList 保存您插入对象的顺序。如果不是,那么可能是 LinkedList。无论如何 - 如果您创建了一个列表,然后循环查看您的视图,将文档 unid 添加到列表中。然后理论上您有一个按视图顺序排列的 Unids 列表。 NotesViewNavigator 和 NotesViewEntry 应该非常快才能做到这一点。现在您将其提供给重复控件以从 UNID 获取文档,然后获取您想要的任何其他值。就个人而言,我会将整个文档转换为 java 对象,但它既不存在也不存在。 那么你会如何影响订单呢?好吧,如果单位的列表在范围内或任何您只需要 Java 方法到 "Move Up" 或 "Move Down" 的地方。我看到了这个问题 Moving items around in an ArrayList 并且看起来有一个 Collections.swap 方法。即使这不是答案,也一定有一些很酷的 Java 解决方案。 无论如何,这不是一个明确的答案,但也许有一些想法供您追求。

(请确保post您得到最终解决方案。)