1

I have a repeat control that contains a button that will process documents that a user selects. My first use case is for deletions. I detect whether or not the user selects at least one document and post an error message if they do not, using view.postScript.

I want to add a confirmation dialog box, confirming that the user wants to take the action on the documents (like delete them) but cannot find a way to do it.

Ideally I want to do this all in my current SSJS.

My code is below, with a stub in for where I want to ask the user for confirmation.

Any help would be greatly appreciated.

//Did the user select a document
var hasSelected:Boolean = false;
for (var id in SelectedDocs.getSelectedIDs()) {     
        hasSelected = true;
        break
}

//If false then set a warning
if (hasSelected == false)
{
x="alert('Error\\n\\nPlease select one or more documents to delete.\\n\\n');";
view.postScript(x)
return
}

//If true then ask confirmation
if (hasSelected == true)
{
}

var rspView:NotesView = database.getView("(dbAllRpPCTasks)")

for (var id in SelectedDocs.getSelectedIDs()) {     

        //Get each selected doc
        var doc:NotesDocument = database.getDocumentByID(id);

        //Get child docs and delete them
        var key:String = doc.getItemValueString("ID");
        var dc:NotesDocumentCollection = rspView.getAllDocumentsByKey(key);
        if (dc.getCount() != 0) 
            {dc.removeAll(true);}

        //Delete the selected doc
        doc.remove(true)
        doc.recycle();
        SelectedDocs.setSelectedState(id,false);
}

Thanks for all the suggestions. I am responding to Frank's answer. Trying to write CSJS that will determine if the user selected docs and then proceed or not.

In the on click event of my button in the CSJS I have the following:

var dtList = document.getElementsByName("#{id:dataView1.getSelectedIds()}");
confirm("What is the length?" + dtList.length);
confirm("Can I get an item?" + dtList.item(0));

It returns a length of zero and the item is undefined.

Bryan Schmiedeler
  • 2,977
  • 6
  • 35
  • 74

3 Answers3

1

Unlike LotusScript, XPages code cannot wait for user input. Think of it like calling an agent to run on server and adding a UIWorkspace.prompt() in there (which will throw an error, because user interaction is not allowed).

The best recommendation would be to add the confirmation prompt as CSJS to the button the users are initially clicking, e.g.

return confirm("Are you sure?");

If they've selected documents, they'll be prompted before they continue. If they have not, it might prompt some users to select the documents anyway. It's hard to have sympathy with complaints from a user who didn't select any documents, clicked that they wanted to continue, then complains at getting another dialog.

Paul Stephen Withers
  • 15,699
  • 1
  • 15
  • 33
  • 1
    Bonus points: use XSP.confirm("...") for better behavior in case your app ends up in XPiNC or other future improvements. – Jesse Gallagher Apr 28 '15 at 13:56
  • Actually my app is in XPiNC. I still would like to put the confirmation right in the SSJS. Can I do this with XSP.confirm? – Bryan Schmiedeler Apr 28 '15 at 15:55
  • 1
    No. SSJS has to run to completion on the server. The whole SSJS runs in the Invoke Application phase, and view.postScript adds CSJS to the "view" Java object, and that code is then picked up during the Render Response phase to be written in the HTML posted back to the server. – Paul Stephen Withers Apr 28 '15 at 19:34
1

Have you tried using Simple Actions for the buttons? I use Confirm Action to verify the user didn't hit a button by accident (a common issue unfortunately). Next, I validate my form and display any messages in a custom message area (Thanks to Tommy Valand) but you can use a normal Message area.

Create an Action Group and place your SSJS expression (or EL) to execute conditionally. Display the message within the page instead of a popup.

Example Action Group Setup

Eric Tomenga
  • 158
  • 2
  • 9
0

A bit of theory - every action can have these combinations:

  • CSJS
  • CSJS + SSJS
  • CSJS + SSJS + CSJS
  • SSJS
  • SSJS + CSJS

So you have to combine one or more actions to accomplish what you want to do. Techniques usable to chain calls:

  • XSP.partialRefreshGet/Post
  • view.postscript (combined with the above)
  • onComplete event's property
  • inline CSJS computed at render phase
  • hidden button initiated by CSJS (postscript/onComplete)
  • ExtLib RPC call

My advice to your use-case is to detect in event's CSJS (before execution) whether user selected any document (DOM operations). If not, use return false; to stop event execution (with proper explanation in CSJS prompt).

Edit: exact use case Divide your use cases to two problems: condition and execution.

1. Condition

Do you REALLY need to call SSJS to get that information? It depends on what you use to select documents - what is your SelectedDocs object? In some cases, you can render (literally) number of selected docs to DOM (assuming selection fires partial/full refresh) and use it in CSSJ before SSJS is called. So rethink your needs/approach.

2. Execution

Does it really need to be SSJS + CSJS + SSJS combination? I doubt so.

Here's example for your use case based on SSJS(+CSJS). It simulates 50:50 chance to show the prompt or delete documents. You get the idea, just update the first action group to get the selected count.

<?xml version="1.0" encoding="UTF-8"?>
<xp:view
    xmlns:xp="http://www.ibm.com/xsp/core"
    xmlns:xp_1="http://www.ibm.com/xsp/coreex">
    <xp:button
        value="Label"
        id="button1">
        <xp:eventHandler
            event="onclick"
            submit="true"
            refreshMode="partial" refreshId="button1">
            <xp:this.action>
                <xp:actionGroup>
                    <xp:actionGroup>
                        <xp:executeScript
                            script="#{javascript:requestScope.docnum = @Integer( @Random() * 2 );}">
                        </xp:executeScript>
                    </xp:actionGroup>
                    <xp:actionGroup
                        condition="#{javascript:requestScope.docnum == 0;}">
                        <xp:executeScript>
                            <xp:this.script><![CDATA[#{javascript:view.postScript('alert("No documents selected...");');}]]></xp:this.script>
                        </xp:executeScript>
                    </xp:actionGroup>
                    <xp:actionGroup
                        condition="#{javascript:requestScope.docnum != 0;}">
                        <xp:executeScript
                            script="#{javascript:// delete documents}">
                        </xp:executeScript>
                    </xp:actionGroup>
                </xp:actionGroup>
            </xp:this.action>
        </xp:eventHandler>
    </xp:button>
</xp:view>
Frantisek Kossuth
  • 3,524
  • 2
  • 23
  • 42
  • Frantisek, I am trying to implement your suggested solution by writing CSJS that will detect if the user selected a doc or not and then either stop execution with an alert if they did not, or continue if they did. – Bryan Schmiedeler May 06 '15 at 18:52
  • Frantisek, I am trying to implement your suggested solution by writing CSJS that will detect if the user selected a doc or not and then either stop execution with an alert if they did not, or continue if they did. This is exactly what I want to do as this solution will apply to many many other use cases that I have. I have been able to get a handle on the dataView in my CSJS but that is all. It shows a length of zero. I need of course the rows and eventually the selectedIDs. But I keep getting a length of 0, and no items. I pasted the code back into my original questions. – Bryan Schmiedeler May 06 '15 at 19:07