I have view panel in my xpages which shows checkbox against each document, now I would like to know how many documents are being selected by user in csjs so I can confirm with user on how many documents are being deleted and same would be part of alert message ( ex, you have selected 10 documents are you want to proceed? )
and then once confirmation is done I will proceed with SSJS to delete them.
Thanks Man
If You just want to count them, then You can use the CSS selector which is beign distributed to view checkboxes by default (unless You changed it explicitly):
function getSelectedCount() {
var checkboxes = dojo.query(".xspCheckBoxViewColumn");
var selectedCount = 0;
for (var i = 0; i < checkboxes.length; i++) {
//check if it is selected
if (checkboxes[i].checked) selectedCount++;
}
return selectedCount;
}
If You need the documents Note IDs, then the elements returned by this query have a "value" property with NoteID:
dojo.query(".xspCheckBoxViewColumn")[0].value // NoteID of first selected element
If You need the array of selected IDs:
function getSelectedIds() {
var checkboxes = dojo.query(".xspCheckBoxViewColumn");
var selectedIds = new Array();
for (var i = 0; i < checkboxes.length; i++) {
if (checkboxes[i].checked) selectedIds = checkboxes[i].value;
}
return selectedIds ;
}
I do something similar but all in ssjs. sessionScope variable store the Note ID which when selected. The count is display on a panel. You use a dialog box to confirm the documents to delete.
Code example:
<xp:viewColumn
id="viewColumn1"
value="">
<xp:checkBox
text=""
id="checkBox1">
<xp:this.readonly><![CDATA[#{javascript:var v = rowData.getColumnValue("ChkInDate");
v == ""?false:true;}]]></xp:this.readonly>
<xp:eventHandler
event="onclick"
submit="true"
refreshMode="partial"
refreshId="panelAction">
<xp:this.action><![CDATA[#{javascript:var rv = rowData.getNoteID();
var vector:java.util.Vector = sessionScope.get("Selected");
var idx = vector.indexOf(rv);
if(idx == -1){
vector.addElement(rv);
}else{
vector.removeElementAt(idx)
}
}]]></xp:this.action>
</xp:eventHandler>
</xp:checkBox>
<xp:this.facets>
<xp:viewColumnHeader
xp:key="header"
id="viewColumnHeader1"
style="text-align:center"
value="Select">
</xp:viewColumnHeader>
</xp:this.facets>
</xp:viewColumn>
Related
I have a strange issue, where I have a simple javascript button, that call's 1 function to write some document history and replace the value of one field. It then does a partial update of a container div ID.
This button works fine when accessed via the UK, however when used by Swiss colleagues, the button is doing nothing.
I have in 1 instance, witnessed it not working for 1 user, only for it to suddenly work later in the day, so I'm stumped as to what the issue may be.
Button Code
<xp:button id="btnProceed" styleClass="btn btn-primary" value="Proceed">
<xp:this.disabled><![CDATA[#{javascript:try{
if (getComponent("chkConfirmed").getValue() == "false") {
return true;
} else {
return false;
}
}catch(e){
openLogBean.addError(e,this);
}
}]]></xp:this.disabled>
<xp:eventHandler event="onclick" submit="true" refreshMode="partial"
refreshId="contentWhiteBackground">
<xp:this.action><![CDATA[#{javascript:var dt = new Date();
var arrHistory:array = AddIndepConfirmationHistoryItem(currentDocument, dt, "Confirmed understanding of the opening guidance", userBean.displayName);
document1.replaceItemValue("showIntroduction", "2");
document1.save();
}]]></xp:this.action>
</xp:eventHandler></xp:button>
Called code
Sub AddIndepConfirmationHistoryItem(confdoc As NotesDocument, dt As Variant, action As String, usrname As String)
Dim hlist As StringList
If Len(confdoc.History(0)) = 0 Then
confdoc.History = IndepConfirmationHistoryItem(dt, action, usrname)
Else
Set hlist = New StringList(confdoc.History, "")
Call hlist.Append(IndepConfirmationHistoryItem(dt, action, usrname))
confdoc.History = hlist.Items
End If
End Sub
EDIT:
function AddIndepConfirmationHistoryItem(doc, dt, action, username){
var ArrDocHistory:array = doc.getItemValueArray("History");
var dateTimeFormat = new java.text.SimpleDateFormat("dd/MM/yyyy kk:mm");
var dateTimeString = dateTimeFormat.format(dt);
if(ArrDocHistory.length < 1){
// This should always return an object as it is created when an objectives document is first
// created but do this check to be safe and create an array if for some reason it doesnt exist
ArrDocHistory = [dateTimeString+"|"+action+"|"+username];
}else{
// append new value to the array
ArrDocHistory.push(dateTimeString+"|"+action+"|"+username);
}
doc.replaceItemValue("History",ArrDocHistory);
doc.replaceItemValue("LastUpdatedByName",username);
doc.replaceItemValue("LastUpdatedDate",dt);
//doc.Save();
}
A check is made on a input field during save, if value exit then it should pass. The input field value exist as a compositeData, but the check keeps failing.
Whats the best way of validating or getting the value of the input field?
I have tried getting this value using the getComponent function.
<xp:inputText id="fieldname" value="#{compositeData.dataSource.fieldname}">
<xp:this.attrs>
<xp:attr name="placeHolder" value="type here"></xp:attr>
</xp:this.attrs>
<xp:eventHandler event="onchange" submit="true" refreshMode="partial" refreshId="inputTextContainer" execId="fieldname">
<xp:this.action><![CDATA[#{javascript:try {
var vVal = getComponent("fieldname").getValue();
viewScope.put("fieldNameScope", vVal);
print("vVal: " + vVal);
}catch(e) {
print("Fieldname error: " + e.toString());
}
}]]></xp:this.action>
</xp:eventHandler>
</xp:inputText>
//var field = getComponent("fieldname").getSubmittedValue(); //returns null.
var field = viewScope.fieldNameScope; //getComponent("fieldname").getValue(); //returns nothing.
if(field == "" || field == null){
vContinue = false;
viewScope.MessageType = "Error";
viewScope.MessageText = "Please field is empty";
return context.redirectToPage( "home.xsp" );
}else{
vContinue = true;
}
I was expecting the check to pass if value exist in the field, but the actual result is null.
I stored the value into a viewscope and then call the viewscope instead of using the getComponent. I will update my question with the onchange eventhandler.
I have 50 radiobuttonGroup in XPages. Field names are sequential like
Field_1, Field_2, Field_3 ... up to 50.
I would like to validate all this fields in one for loop. Please find what i have tried so far but i could not solve syntax. is it possible or I am running in circles.
<xp:button id="btnSave"
styleClass="btn btn-icon btn-primary">
<i class="fa fa-share" aria-hidden="true"></i>
<xp:eventHandler event="onclick"
submit="false">
<xp:this.script><![CDATA[for (var c=1; c<50; c++)
{
var fID = "\#{id:Question_"+ c +"}";
var elements = document.getElementsByName(fID);
alert(elements);
var syc = 0;
for(i=0; i<elements.length; i++)
{
if (elements[i].checked == false)
{
syc += 1;
}
}
if (elements.length==syc)
{
alert("Please select a value for question " + c);
return false;
}
}
]]></xp:this.script>
</xp:eventHandler>
</xp:button>
<xp:radioGroup id="Question_1" value="#{document1.Question_1}">
<xp:selectItem itemLabel="One" itemValue="One"></xp:selectItem>
<xp:selectItem itemLabel="Two" itemValue="Two"></xp:selectItem>
</xp:radioGroup>
Change the approach and give the input fields a common class. Then you get the collection of all fields to validate and loop through them.
You will need to check the name (radio buttons with the same name but different Id form a group) to get the grouping right.
I would loop through them and create an object with the names as property names that are set to true if the radio button is checked and created if not checked but missing.
At the end you have one js object with all Boolean properties. If one is false validation went wrong and you get the elements by name and add the class aria-invalid for the error
The cards above are populated via a repeat and the view is not categorised. What I want to add now is the ability to append a delete flag to any of the card in any order.
Below is the code for the delete button:
<xp:link>
<span class="glyphicon glyphicon-trash pull-right text-primary"></span>
<xp:eventHandler event="onclick" submit="true" refreshMode="complete">
<xp:this.action><xp:actionGroup><xp:executeScript>
<xp:this.script><![CDATA[#{javascript:
var name=getComponent("FullName").getValue();
var vec:NotesView = database.getView("SupportTeam");
var docEv:NotesDocument = vec.getFirstDocument();
if (name == docEv.getItemValueString("FullName")) {
docEv.replaceItemValue("SupportAction", "Delete");
docEv.save();
}
}]]></xp:this.script>
</xp:executeScript>
</xp:actionGroup>
</xp:this.action></xp:eventHandler>
</xp:link>
The code above works, but the delete button need to be clicked twice for it work and it has to be in the order, that is if 'Test 6' is clicked it will not delete since 'Test 5' is in the way.
I tried using the getdocumentbykey() but the view will need to be categorised which will then show multiple entries. In this case, it will display lots of blank cards.
Your help will be appreciated.
We need to see your repeat code, however, aslong as you set the var property of your repeat to something, that then makes row data available to you, so you could use something like:
var id = rowData.getUniversalID();
var docEv:NotesDocument = database.getDocumentByUNID(id);
docEv.replaceItemValue("SupportAction", "Delete");
docEv.save();
//Or to do a hard delete
docEv.remove(true);
I decided to loop through the collection twice using the while loop to get the collection and then the for loop for the action and that seems to work, but I'm sure there should be a better way of doing this.
Below is the final code:
var name = getComponent("FullName").getValue();
var vec:NotesView = database.getView("SupportTeam");
var docEv:NotesDocument = vec.getFirstDocument();
var collection = [];
while (docEv != null){
try{
var member = docEv.getItemValueString("SupportFullName"), memberLength = collection.length;
collection.push(member);
for (var i = 0; i < memberLength; i++) {
if(memberLength != null && name == docEv.getItemValueString("SupportFullName")){
docEv.replaceItemValue("SupportAction", "Delete");
docEv.save();
}
}
}catch(e){
print("error: " + e.toString());
}
var tmp = vec.getNextDocument(docEv);
docEv.recycle();
docEv = tmp;
}
Thanks for all the response.
I have a combo box its values are 10, 20, 30, 40, 50 when I create a document and display it in a view the number is appeared but I want to display its labels (labels are text) not numbers.
Can someone please help me find out how to solve this issue.
Thanks
I tend to add values of a given checkbox into a Resource Bundle, and then access that Resource Bundle both from the xp:selectItems and the xp:viewColumn values.
First, I'll create a Resource Bundle which I set as "label", with the following values:
itemsList_status=Draft|0,Published|1,Archived|-1
itemsList_delimiter=,
Here's an example of the xp:selectItems for an xp:combobox:
<xp:selectItems>
<xp:this.value>
<![CDATA[#{javascript:return getSelectItems('status');}]
</xp:this.value>
</xp:selectItems>
Here's my getSelectItems() SSJS function:
var getSelectItems : function(key) {
try {
var returnObj = new Array();
var items = null;
switch(key) {
case "status" :
items = #Text(label.itemsList_status).split(label.itemsList_delimiter);
break
}
for( var n=0, l=items.length; n < l; n++) {
returnObj.push(items[n]);
}
return returnObj;
} catch(e) {
print(database.getTitle() + " SSJS Error for getSelectItems()");
print(e.toString());
}
}
Run this function, and it'll return 3 options that read Draft, Published, and Archived while actually storing 0, 1, and -1 respectively. The problem that you're running into - and what using this abstracted method of storing your labels:values in a Resource Bundle + SSJS to address - is when you go to read the value but actually want to display the label...
Here's my getSelectedValue() function:
var getSelectedValue : function(key, thisValue) {
try {
var returnObj = new Array();
var items = null;
switch(key) {
case "status" :
items = #Text(label.itemsList_status).split(label.itemsList_delimiter);
break
}
var s = "";
var l = "";
for( var n=0, i=items.length; n < i; n++) {
if(items[n].indexOf("|") == -1) {
s = items[n];
l = items[n];
} else {
s = items[n].split("|").pop();
l = items[n].split("|").shift();
}
if(thisValue == s) {
return l;
}
}
return thisValue;
} catch(e) {
print(database.getTitle() + " SSJS Error for getSelectedValue()");
print(e.toString());
}
}
Now you'd pass the current value and the desired label:value Resource Bundle item handle, and this function spits out the correlating label. Here is how I use it in an xp:viewColumn:
<xp:viewColumn
id="viewColumn_status">
<xp:this.value><![CDATA[#{javascript:return ""}]]></xp:this.value>
<xp:text
value="#{javascript: return
getSelectedValue('status',thisEntry.getDocument().getItemValueString('status'))}" />
<xp:viewColumnHeader
value="#{label.viewColumnHeader_posts_status}"
id="viewColumnHeader_status">
</xp:viewColumnHeader>
</xp:viewColumn>
... and that's about it - the Resource Bundle entry to "itemList_status" acts as the authoritative master for the label:value pairs, so you just check that for the input building and deconstruct it for the labeling of stored values.
Hope this helps!
Using aliases is analog to the usage in a normal form.
Use a formula item for the values:
return ["- Please select -|", "ten|10", "twenty|20", "thirty|30"];
But keep in mind that the values that is stored is always TEXT and not a number.