I created an ALV TREE report, using cl_gui_alv_tree, that has 3 levels. I'm also implementing an event handler for when he double clicks a node.
My problem is that I want to take some actions only when he double clicks a node that is a root node. The event 'node_double_click' gives a node_key, but that's the index of the displayed table. How could I achieve this?
The node ID is not an index, it's the ID you assigned to the node when adding it to the tree.
If possible, I'd suggest switching to CL_SALV_TREE - not only because it is documented
and supported by SAP, but also because it comes with some query methods that are quite handy. These methods are documented as well. You can use, for example, GET_NODE to retrieve a node by its ID and then use GET_PARENT to check whether the node in question is a top-level node or has a parent node it is attached to.
I created a pattern for myself, which i am using.
lv_parent1 = node_key.
while lv_parent1 ne go_Main_tree->C_VIRTUAL_ROOT_NODE.
CALL METHOD go_main_tree->get_parent
EXPORTING
i_node_key = lv_parent1
IMPORTING
e_parent_node_key = lv_parent1.
lv_hierlevel = lv_hierlevel + 1 .
ENDWHILE.
if lv_hierlevel > 2.
“ do what You want to do
endif.
Related
I am trying to patch a calendar event with the Microsoft Graph API (from a Node express app).
I create a new event with client.api('/me/events').post(myEvent) and it works just fine (I see it appear in my calendar). The return value has an ID which is:
AAMkADc0Yjg2ODdmLTlkNDQtNGQ0Yi1iNjBmLTE1MDdmYzI4MGJkOABGAAAAAADt0ZJy6xMCRq23C8icFGeqBwAOM3XMH4d2SYMQ5psbvFytAAAAAAENAAAOM3XMH4d2SYMQ5psbvFytAAJ_B-B7AAA=
I then use client.api('/search/query').post(myQuery) to find the event based on some criteria, and this works fine. I receive an array of hits, with only one hit (which actually is the freshly created event, looking at the subject and body), and with a hitId equal to:
AAMkADc0Yjg2ODdmLTlkNDQtNGQ0Yi1iNjBmLTE1MDdmYzI4MGJkOABGAAAAAADt0ZJy6xMCRq23C8icFGeqBwAOM3XMH4d2SYMQ5psbvFytAAAAAAENAAAOM3XMH4d2SYMQ5psbvFytAAJ+B/B7AAA=
For some reason I don't understand why the 2 IDs are not fully identical: the _ is changed to +and -changed to /.
I now want to modify the event, and try to update it with
let newVal = hits[0].resource // hits is coming from the result returned by the search query
newVal.id = hits[0].hitId // needed because the 'resource' does not contain the id
client.api('/me/events/'+hitId).patch(newVal)
But I get an error: Resource not found for the segment 'B7AAA='.
Could you please tell me how to make the patch work (and explain why the ID from the search is not strictly like the one created). I have read several examples in the documentation (such as https://learn.microsoft.com/en-us/graph/search-concept-events) but I could not find a solution.
Many thanks!
So what is happening here is, PATCH /me/events/{hitId} is being resolved by Graph API such that the forward slash in the hitId denotes a path and Graph ends up using B7AAA= as a resource id hence the error Resource not found for the segment 'B7AAA='.
A work around that might work is to replace / in hitId(s) with %252F. You can do it like this.
client.api(`/me/events/${hitId.replace('/', '%252F')}`).patch(patch)
There is already this Issue on GitHub for documentation on how to handled these base64 encoded resource ids with /
As for the two IDs being non identical, Graph API will accept both of them and resolve to the same resource. I have no idea why they are different though.
In v2 it was possible to make a call to /files with the query fileId in children to get a list of DriveFile objects that were parents of the supplied file.
Now, it seems to be required to make a call to /files/:fileId?fields=parents, then make a separate call to /files/:parentId for each returned parent, possibly turning one call into a dozen.
Is this correct, and if so why? This is a huge performance hit to our app, so hopefully there's an undocumented method.
The query "'fileId' in children'" doesn't publicly exist (not documented/supported) in v2 either and I don't recall it ever existing. What does exist in V2 is the Parents collection which effectively answers the same question. In v3, to get the parents of a file you just get the child and ask for the parents field.
As for whether or not that is a performance hit, I don't think it is in practice. The Parents resource in v2 was very light to begin with, and other than the ID the only useful field was the 'isRoot' property. That you can calculate yourself by calling files/root up front to get the ID of the root folder for that user (just once and save it, it won't change for that user.)
If you need to get more information about the parents than just the IDs and are worried about the # of calls you have to make, use batching to fetch them. If you just have one parent, no need to batch (it's just overhead.) If you find that a file has multiple parents, create a batch request. That'll be sent as a single HTTP request/response and is handled very efficiently on the back end.
Point is, if you just need IDs, it's no worse than before. It's one call to get the parents of a file.
If you need more than IDs, it's at most 2 HTTP requests (outside really bizarre edge cases like 1000+ parents which would exceed the batch size :)
In V3 it is possible to list all children of a parent as it's explained here: https://developers.google.com/drive/v3/web/search-parameters
Example call:
https://www.googleapis.com/drive/v3/files?q=parents in '0Byho0qAdzabmVl8xcDR1S0pNY3c' of course replace spaces with %20, this will list all the files in the folder which has id='0Byho0qAdzabmVl8xcDR1S0pNY3c'
you just need to mention like below:
var request = service.Files.List();
request.Q = "('root' in parents)";
var FileListOfParentOnly = request.Execute();
I've been searching the web, but I can't figure out how to get a tree view of the items on an OPC server. I used the following code:
using Opc.Da;
using Server=Opc.Da.Server;
using Factory=OpcCom.Factory;
string urlstring = string.Format("opcda://{0}/{1}/{{{2}}}", _hostName, _serverName, serverid);
Server s = new Server(new Factory(), new URL(urlstring));
ItemIdentifier itemId = null;
BrowsePosition position;
BrowseFilters filters = new BrowseFilters() {BrowseFilter = browseFilter.item};
BrowseElement[] elements = s.Browse(itemId, filters, out position);
You do not state what precisely does not work. However, the main problems is probably in the fact that you are using BrowseFilter = browseFilter.item. The nodes in the tree are either leaves (sometimes called items), or branches. Your code only asks for the leafs, under the root of the tree. There may be no items under the root whatsoever, and you need to obtain the branches as well, and then dwelve deeper into the branches, recursively.
Start by changing your code to use BrowseFilter = browseFilter.all. This should give you all nodes under the root. Then, call the Browse recursively for the branches (just branches, not items) you receive, using the item ID of each branch as the starting point for the new browse.
I'm working on creating a custom report report page in CQ5. I've got my reportbase and columnbase components set up correctly, by following the steps listed here. I am able to, for instance, pick up all the templates that are available, by setting the property nodeTypes to cq:Template
I want to add a constraint to it, say for example pick up templates whose jcr:title is foo. I created a node under querybuilder called propertyConstraints and added my constraints in the form of nodes below it, as describedhere. However, this does not work for me at all.
What is the correct way to add constraints to the querybuildernode? Has anyone tried this?
Also, once I get this working correctly, can I extend this example to return pages of a specific template?
Have you looked into the QueryBuilder API? Adobe's documentation discusses how to match 1 or more property values.
Create a node propertyConstraints under queryBuilder of type nt:unstructured
create another node under propertyConstraints with any name.
Add properties to this node :
name String jcr:title
value String foo
I am displaying a list of items using a SAP ABAP column tree model, basically a tree of folder and files, with columns.
I want to load the sub-nodes of folders dynamically, so I'm using the EXPAND_NO_CHILDREN event which is firing correctly.
Unfortunately, after I add the new nodes and items to the tree, the folder is automatically collapsing again, requiring a second click to view the sub-nodes.
Do I need to call a method when handling the event so that the folder stays open, or am I doing something else wrong?
* Set up event handling.
LS_EVENT-EVENTID = CL_ITEM_TREE_CONTROL=>EVENTID_EXPAND_NO_CHILDREN.
LS_EVENT-APPL_EVENT = GC_X.
APPEND LS_EVENT TO LT_EVENTS.
CALL METHOD GO_MODEL->SET_REGISTERED_EVENTS
EXPORTING
EVENTS = LT_EVENTS
EXCEPTIONS
ILLEGAL_EVENT_COMBINATION = 1
UNKNOWN_EVENT = 2.
SET HANDLER GO_APPLICATION->HANDLE_EXPAND_NO_CHILDREN
FOR GO_MODEL.
...
* Add new data to tree.
CALL METHOD GO_MODEL->ADD_NODES
EXPORTING
NODE_TABLE = PTI_NODES[]
EXCEPTIONS
ERROR_IN_NODE_TABLE = 1.
CALL METHOD GO_MODEL->ADD_ITEMS
EXPORTING
ITEM_TABLE = PTI_ITEMS[]
EXCEPTIONS
NODE_NOT_FOUND = 1
ERROR_IN_ITEM_TABLE = 2.
It's been a while since I've played with SAP, but I always found the SAP Library to be particularly helpful when I got stuck...
I managed to come up with this one for you:
http://help.sap.com/saphelp_nw04/helpdata/en/47/aa7a18c80a11d3a6f90000e83dd863/frameset.htm, specifically:
When you add new nodes to the tree model, set the flag ITEMSINCOM to 'X'.
This informs the tree model that you want to load the items for that node on demand.
Hope it helps?
Your code looks fine,
I would use the method ADD_NODES_AND_ITEMS myself if I were to add nodes and items ;)
Beyond that, try to call EXPAND_NODE after you added the items/nodes and see if that helps.