How to find parameters of an Action Menu created at runtime - delphi-10.1-berlin

My program creates Action Menu items at runtime, with the caption of each item set to a value returned by a database query.
The OnExecute procedure is the same for all items.
When I click on an item, I want to obtain the item caption to use in the OnExecute procedure.
I have tried the following (analogous to TMenuItem for a popup menu):
sCaption := TActionClientItem(Sender).Caption;
However, this always returns an empty string.
I have searched the web and the Delphi Help to no avail. I am aware that Caption is a published property, but the public property Index also fails.
I presume I am doing something wrong here, but cannot figure out what.

The information provided is not so detailed, but I guess the OnExecute procedure that you are describing is the event from a TAction which is included in a TActionManager.
The problem is that the Sender of the OnExecute event is the TAction that it is just clicked! So when you are casting the TActionClientItem to the Sender
TActionClientItem(Sender)
it gives you nothing.
Quick solution would be first to create the TAction(s), give them the caption you wish and then assign those TActions to your TActionClientItem(s). They will get automatically the Caption of the assigned Actions.
actionClientItem1.Action := Action1;
You get then your caption on the event
sCaption := TAction(Sender).Caption;

The problem with the suggested answer of creating an Action for each item is that I wish to use the same action for many items (the number determined by a database query count). The action is then modified by the value of the caption, being the value of each record of the database query.
However, the following answer has been suggested to me. I have tested this and it works:
"If the items are on the TActionMainMenuBar component then you can do the following:
type
TCustomActionMenuBarAccess = class(TCustomActionMenuBar);
In the Action Execute you can then do:
if TCustomActionMenuBarAccess(ActionMainMenuBar1).FSelectedItem <> nil then
ShowMessage('Selected Item: ' + TCustomActionMenuBarAccess(ActionMainMenuBar1).FSelectedItem.Caption);
where ActionMainMenuBar1 is the name of the TActionMainMenuBar component on the form.
If the items are created on a toolbar, then you can use the TAction(Sender).ActionComponent property as the TAction is the sender in these cases."

Related

XPages setfield from view selection

I have a repeat control with buttons to select or deselect various docs - that works and I can identify each selected doc by the doc id. I have another button with the following SSJS. For the docs selected I want to set a field in the underlying doc. This script works if I do a simple doc.removePermanently(true)... but not if I try to manipulate a common field value for the selected docs. I'm getting an Error 500 HTTP Web Server: Command Not Handled Exception. What is the proper way to do this?
var docsForAction = sessionScope.get("myList");
var doc:NotesDocument;
for(i=0; i < docsForAction.length; i++){
doc = database.getDocumentByUNID(docsForAction[i]);
doc.setValue("Level","10");
}
docsForAction = [];
viewScope.put("myList", docsForAction);
context.reloadPage();
You're probably getting an error 500 because you don't have an error page defined. Go to Xsp Properties and tick "Display default error page". You will then get a more meaningful error page displayed.
The error you'll see is probable on the setValue() line, the message being "null". That's because setValue() is not a method of NotesDocument, it's a method of the dominoDocument datasource (the "NotesUIDocument" XPages equivalent, if you know LotusScript).
Casting the variable (adding ":NotesDocument") is good because it allows you to take advantage of the typeahead support in the SSJS editor or the source pane. That will give you a list of valid methods and the valid parameter types taken.

I would like to print selected documents from a view

Does anyone have a suggestion on how to print selected documents in an simple xPages view. I'm converting a legacy application. Which used the following Lotus script code to print. Thanks
Set db = session.CurrentDatabase
Set collection = db.UnprocessedDocuments
count = collection.count
If count = 0 Then
Goto errSelectDocs
End If
Stop
For i = 1 To count
'
Set note = collection.GetnthDocument (i)
Set Source2 = w.EditDocument( False, note )
Set Source3 = w.ComposeDocument("","","mRecensement imp")
Call Source3.print(1)
Call Source3.close
Call Source2.close
'----------------------------------
nextdocument:
Next
I'm going to answer here rather the following up in the comments of the Simon answer.
so ok. We're saying build a new page with a repeat control of the select documents. and the question asker is saying, I THINK, that it seems wrong to do:
doc:NotesDocument=database.getDocumentByID(rowData);
return doc.getItemValue("xxxx") for 30 + items
right. You don't want to do that. should work. But icky to do.
Probably what I would do is create a SSJS function to pass rowData into. In that function build an array. Load the document once... put all the items into the array and pass them back to the page with the repeat control.
Probably what you do then is have a panel and use either a dataContext or objectData that's bound to the panel. Inside the panel is your page and fields. Those fields just read from the dataContext or objectData. so you're only getting the document once. I guess you could even use just a scoped variable though I don't think there's an event to call code on each row. So you'd need to hack it into the first field maybe or something.
But that's what you want. I previously asked a question on StackOver flow about returning multiple parameters like this: How to pass variable parameters to an XPages SSJS function?
Maybe that's helpful.
Someone might come up with a better solution but one option is this.
First have your viewPanel on your first XPage. Select your documents and click a button. The code would do this.
var viewPanel = getComponent("viewPanel1");
sessionScope.documentIDs = viewPanel.getSelectedIds();
You then hand it off to another XPage which has a repeat control of the print structure for a document. It reads the document ID's and creates the page. Then just use the normal print command after loading.
window.print();

Inline Editing of View data used in a repeat

I have a repeat control using a view as the datasource with a custom control within the repeat. The custom control is made up of a panel with two tables. One table has computed fields with an Edit button and the other has editable fields with a Save and Cancel button. The Edit and Cancel buttons work as needed, but the Save button gives a NotesDocument.save() is null error. I have already narrowed the issue down to the error occurring on the edoc.save() line by commenting out all prior lines. I even tried to do an edoc.lock(), but got the same error.
var edoc:NotesDocument = database.getDocumentByUNID(viewScope.get('docid'));
edoc.replaceItemValue('Ext_1',viewScope.get('ext_1'));
edoc.replaceItemValue('DID',viewScope.get('did'));
edoc.replaceItemValue('Mobile',viewScope.get('mobile'));
try {
edoc.save();
} catch(e) {
print(e.toString());
}
The storage of a DocID in the viewScope and a repeat control doesn't seem right. You want to add a custom property to your custom control called DocID and then instead of
database.getDocumentByUNID(viewScope.get("docid"));
You do:
database.getDocumentByUNID(compositeData.DocID);
This was you can be sure that you get the document that was in that view for that row.
What you also might consider, instead of all the manual steps (the ones you commented out) have a panel with a DocumentDataSource and then simply bind your input fields to that one. Handover of id via custom property and "IgnoreRequestParameter = true
Then you simply do a rowDoc.save() (presuming you named the datasource rowDoc) and you don't need to recycle anything. Let us know how it goes.

java.util.ArrayList incompatible with [Ljava.lang.Object check box group

I have a Check box group, whose values are computed by using the selected values of another Check box group. So when I do
var check6:com.ibm.xsp.component.xp.XspSelectManyCheckbox = getComponent("check6");
ArrSelected = check6.getSelectedValues();
to get the selected values, the following exception occurs:
Error calling method 'getSelectedValues()' on java class 'com.ibm.xsp.component.xp.XspSelectManyCheckbox'
java.util.ArrayList incompatible with [Ljava.lang.Object;
Check6 gets its values from a session scope variable that is computed on beforePageLoad event and I have also set the default value.
Note that this does not happen onload of the page, but when the first partial refresh happens. Does anyone know what this exception indicates?
Thanks a lot!
Bind the value of the selectItems for the second check box group to precisely the same expression the first checkbox group's value attribute is bound to.
This article provides a lengthy description of the reason why, but here's a very quick summary: if you ask a component what its value is, it has to ask the data it's bound to. So skip the component, and ask the data yourself.
So, if your first group looks like this:
<xp:checkBoxGroup value="#{currentDocument.FirstField}">...
Then your second group should look like this:
<xp:checkBoxGroup value="#{currentDocument.SecondField}">
<xp:selectItems value="#{currentDocument.FirstField}">
</xp:checkBoxGroup>
When the user's selection in the first group is posted to the data source, the second group will reflect the changes because they're linked to the same property on that data source. Slight caveat: if your page includes any required fields, you may need to skip validation on the onchange event that triggers the second group to recalculate.
the reason is simple, this class has no method getSelectedValues() (as far as I can see it, look here for more info: http://public.dhe.ibm.com/software/dw/lotus/Domino-Designer/JavaDocs/XPagesExtAPI/8.5.2/index.html?overview-summary.html)
Maybe you could bind the control to a scoped variable and then access this variable to compute your other values?

Using an event receiver to update an item's 'Title' field

I have written an event receiver that is activated on the 'ItemAdded' event of a 'Pages' list. The code runs fine, but my issue is this - during the call to my Sub ItemAdded, I want to change the value of a field belonging to the current list item (in this case an aspx page).
The idea is that I can configure the 'Title' field to be another value, which my event receiver configures, and by the time the user sees the page in edit mode, the new title will have been saved for the page. Here is my current attempt:
Public Overrides Sub ItemAdded(ByVal properties As Microsoft.SharePoint.SPItemEventProperties)
Dim newItem As SPListItem = properties.ListItem
Dim currentSiteTitle As String = properties.OpenWeb().Title
UpdateItemTitle(newItem, currentSiteTitle)
newItem.Update()
'newItem.SystemUpdate()
End Sub
As you can see, I've tried both Update() and SystemUpdate(), but in each case, when the user tried to check in the page, they get a message that the page has been modified externally. Plus, when viewing the page, the title field value has not changed.
Is what I'm trying to do at all possible, or is there a better way?
Cheers.
Jas.
changing the properties.afterproperties will get around the save conflict. note that the afterproperties is a hashtable, but you can access it so:
properties.AfterProperties["Title"] = "My New Title";
ItemAdded Name says it all. It a Asynchronous Event that happens after the Items has been added, so is the issue with your calse. I suggest you to hook the ItemAdding event unless you have reason not to do so.
Refer the Link for Details on Asynchronous & Synchronous
The best way to accomplish this is use the ItemAdding event. This will allow you to change the Title value before it is saved to the database. Trying to change them in ItemAdded is possible but will cause the headaches you are experiencing.
Have you tried ItemAdding?
Now following on from the above, I found that when I was working with a discussion group the only place I could change any fields in the list item was in the ItemUpdating method, where I could assign the new value into the properties.AfterProperties hash corresponding to the item name as mentioned previously.
Unfortunately this didn't seem to automatically be run when a new reply was added to the discussion ( maybe it is in other list related scenarios ) but if I put code into the ItemAdded method ( ItemAdding was not being triggered either ) I found that it was being run but that I couldn't change the item from there, so I ended up with something like this in itemAdded:
public override void ItemAdded(SPItemEventProperties properties)
{
SPListItem item = properties.ListItem;
item.Update();
}
The outcome of this is that the field is updated but not before it is shown so that when the user is directed to the output page the list will look as it did before but if you change view or look at the details for the reply you will find that it has actually changed as it was supposed to.
This is good enough for me as I'm expecting most of my replies to arrive by email.

Resources