
{"id":223,"date":"2017-05-02T22:36:09","date_gmt":"2017-05-02T12:36:09","guid":{"rendered":"http:\/\/bakke.online\/?p=223"},"modified":"2017-05-02T22:36:09","modified_gmt":"2017-05-02T12:36:09","slug":"how-to-tree-lookups-in-dynamics-ax-reference-group-controls-part-4","status":"publish","type":"post","link":"https:\/\/www.bakke.online\/index.php\/2017\/05\/02\/how-to-tree-lookups-in-dynamics-ax-reference-group-controls-part-4\/","title":{"rendered":"How-to: Tree lookups in Dynamics AX reference group controls, part 4"},"content":{"rendered":"<p>This is something that keeps coming up on different projects, so I\u2019d like to share how I usually do this. \u00a0There are some examples out there which try to describe a very generic solution which can be used in almost any case. \u00a0However, such solutions very quickly become <strong>very<\/strong> complex. \u00a0To keep things simple, I have tried to keep this example fairly specific but adaptable to a wide range of circumstances. \u00a0Specifically this example is using a fixed hierarchy structure with a fixed number of levels, each of which will be represented by a different table.<\/p>\n<p>If you have not read the first 3 parts ( <a href=\"https:\/\/www.bakke.online\/index.php\/2017\/04\/11\/how-to-tree-lookups-in-dynamics-ax-reference-group-controls-part-1\/\">1<\/a>, <a href=\"https:\/\/www.bakke.online\/index.php\/2017\/04\/12\/how-to-tree-lookups-in-dynamics-ax-reference-group-controls-part-2\/\">2<\/a>, <a href=\"https:\/\/www.bakke.online\/index.php\/2017\/05\/02\/how-to-tree-lookups-in-dynamics-ax-reference-group-controls-part-3\/\">3<\/a> ) of this tutorial yet, I recommend you do that first, to help with the understanding of this post, which explains how to automatically navigate to the currently selected item in the tree lookup. \u00a0This is something which is quite easy to do in a traditional lookup but requires a bit more work when dealing with trees.<\/p>\n<p><!--more--><\/p>\n<h3>Searching, searching&#8230;<\/h3>\n<p>We&#8217;ll need a way to find and automatically expand all ancestor tree items based on the currently selected shelf. \u00a0We have the shelf record ID in the books, and we can use that to find the shelf, then the rack, aisle and all the way up to the library.<\/p>\n<p>However, the tree is not loaded all at once, but on demand as we expand items. \u00a0Thus, we have to expand from the top down, and narrow down to the correct record as we go.<\/p>\n<p>Add a new method called findShelf to the EB_ShelfLookup form:<\/p>\n<pre><span style=\"color: #0000ff;\"><strong>public void<\/strong><\/span> findShelf( EB_ShelfRefRecId _shelfRecId )\n{\n  EB_Shelves   shelves;\n  EB_Racks     racks;\n  EB_Aisles    aisles;\n  int          idx;\n  FormTreeItem item;\n\n  <span style=\"color: #0000ff;\"><strong>select firstOnly<\/strong><\/span> RecId\n    <span style=\"color: #0000ff;\"><strong>from<\/strong> <\/span>shelves\n   <span style=\"color: #0000ff;\"><strong>where<\/strong> <\/span>shelves.RecId == _shelfRecId\n    <span style=\"color: #0000ff;\"><strong>join<\/strong> <\/span>RecId\n    <span style=\"color: #0000ff;\"><strong>from<\/strong> <\/span>racks\n   <span style=\"color: #0000ff;\"><strong>where<\/strong> <\/span>racks.RecId == shelves.RackRecId\n    <span style=\"color: #0000ff;\"><strong>join<\/strong> <\/span>RecId, LibraryRecId\n    <span style=\"color: #0000ff;\"><strong>from<\/strong> <\/span>aisles\n   <span style=\"color: #0000ff;\"><strong>where<\/strong> <\/span>aisles.RecId == racks.AisleRecId;<\/pre>\n<p>The tree keeps the RecId for each record in the data() property for the items. \u00a0All we need in order to find our way through the tree is the record ID for each level, and we retrieve that through a simple joined query. \u00a0Note that we don&#8217;t actually need to retrieve anything from the library table, we just need the RecId which we can find in EB_Aisles.LibraryRecId.<\/p>\n<p>Next, we find the library item at the root-level of the tree.<\/p>\n<pre><span style=\"color: #008000;\"><em>\/\/ Look for the library<\/em><\/span>\nidx = Tree.getChild( <span style=\"color: #ff0000;\"><strong>0<\/strong><\/span> );\n<span style=\"color: #0000ff;\"><strong>while<\/strong><\/span>( idx != <span style=\"color: #ff0000;\"><strong>0<\/strong><\/span> )\n{\n  item = Tree.getItem( idx );\n  <span style=\"color: #0000ff;\"><strong>if<\/strong><\/span>( item.data() == aisles.LibraryRecId )\n  {\n    Tree.expand( idx, FormTreeExpand::Expand );\n    <span style=\"color: #0000ff;\"><strong>break<\/strong><\/span>;\n  }\n  idx = Tree.getNextSibling( idx );\n}<\/pre>\n<p>We start by getting the first child of the zero-index, which gives us the index of the first root-level item. \u00a0We then get the item for that index and compare it to the library record ID. \u00a0If it is a match, we expand that item and break out of the loop. \u00a0Otherwise we grab the next sibling item until we&#8217;ve seen them all.<\/p>\n<p>Expanding the item will in turn load the child items. \u00a0This happens behind the scenes, so we don&#8217;t have to worry about it and can proceed to searching for the correct aisle:<\/p>\n<pre><span style=\"color: #0000ff;\"><strong>if<\/strong><\/span>( idx != <span style=\"color: #ff0000;\"><strong>0<\/strong><\/span> )\n{\n  <span style=\"color: #008000;\"><em>\/\/ Look for the aisle<\/em><\/span>\n  idx = Tree.getChild( idx );\n  <span style=\"color: #0000ff;\"><strong>while<\/strong><\/span>( idx != <span style=\"color: #ff0000;\"><strong>0<\/strong><\/span> )\n  {\n    item = Tree.getItem( idx );\n    <span style=\"color: #0000ff;\"><strong>if<\/strong><\/span>( item.data() == aisles.RecId )\n    {\n      Tree.expand( idx, FormTreeExpand::Expand );\n      <span style=\"color: #0000ff;\"><strong>break<\/strong><\/span>;\n    }\n    idx = Tree.getNextSibling( idx );\n  }<\/pre>\n<p>We start out by verifying that we did indeed find the library. \u00a0Unless we have an inconsistent tree structure we will always find the ancestor items, but it is good practice to\u00a0confirm. \u00a0The structure of the loop is the same, but we start by getting the first child item of the library item and we compare against the aisle record ID instead.<\/p>\n<p>Now we repeat for the rack:<\/p>\n<pre><span style=\"color: #0000ff;\"><strong>if<\/strong><\/span>( idx != 0 )\n{\n  <span style=\"color: #008000;\"><em>\/\/ Look for the rack<\/em><\/span>\n  idx = Tree.getChild( idx );\n\n  <span style=\"color: #0000ff;\"><strong>while<\/strong><\/span>( idx != 0 )\n  {\n    item = Tree.getItem( idx );\n    <span style=\"color: #0000ff;\"><strong>if<\/strong><\/span>( item.data() == racks.RecId )\n    {\n      Tree.expand( idx, FormTreeExpand::Expand );\n      <span style=\"color: #0000ff;\"><strong>break<\/strong><\/span>;\n    }\n    idx = Tree.getNextSibling( idx );\n  }<\/pre>\n<p>Finally we get to the shelf:<\/p>\n<pre><span style=\"color: #0000ff;\"><strong>      if<\/strong><\/span>( idx != <span style=\"color: #ff0000;\"><strong>0<\/strong><\/span> )\n      {\n        <span style=\"color: #008080;\"><em>\/\/ Look for the shelf<\/em><\/span>\n        idx = Tree.getChild( idx );\n\n        <span style=\"color: #0000ff;\"><strong>while<\/strong><\/span>( idx != <span style=\"color: #ff0000;\"><strong>0<\/strong><\/span> )\n        {\n          item = Tree.getItem( idx );\n          <span style=\"color: #0000ff;\"><strong>if<\/strong><\/span>( item.data() == shelves.RecId )\n          {\n            Tree.select( idx );\n            <span style=\"color: #0000ff;\"><strong>break<\/strong><\/span>;\n          }\n          idx = Tree.getNextSibling( idx );\n        }\n      }\n    }\n  }\n}<\/pre>\n<p>Again, the loop works the same as above, but instead of expanding the item we will select it. \u00a0After that we can return from the method.<\/p>\n<h3>Hooking it up<\/h3>\n<p>In order for this to work automatically when the lookup is opened, we need to make a few changes to the form&#8217;s init() method as well.<\/p>\n<pre><span style=\"color: #0000ff;\"><strong>public void<\/strong><\/span> init()\n{\n<span style=\"border-left: solid thick #FF0000;\">  FormReferenceGroupControl callerControl;<\/span>\n\n  <span style=\"color: #0000ff;\"><strong>super<\/strong><\/span>();\n\n  imageListAppl = <span style=\"color: #0000ff;\"><strong>new<\/strong> <\/span>ImageListAppl( <span style=\"color: #ff0000;\"><strong>32<\/strong><\/span>, <span style=\"color: #ff0000;\"><strong>32<\/strong> <\/span>);\n  imageListAppl.add( <span style=\"color: #ff0000;\"><strong>12039<\/strong> <\/span>);\n  imageListAppl.add( <span style=\"color: #ff0000;\"><strong>12040<\/strong> <\/span>);\n  imageListAppl.add( <span style=\"color: #ff0000;\"><strong>12041<\/strong> <\/span>);\n  imageListAppl.add( <span style=\"color: #ff0000;\"><strong>12047<\/strong> <\/span>);\n\n  Tree.setImagelist( imageListAppl.imageList() );\n\n\u00a0 EB_Libraries::buildTree( Tree, imageListAppl );\n\n<span style=\"border-left: solid thick #FF0000;\">  callerControl = element.selectTarget();<\/span>\n<span style=\"border-left: solid thick #FF0000;\">  <span style=\"color: #0000ff;\"><strong>if<\/strong><\/span>( callerControl != <span style=\"color: #0000ff;\"><strong>null<\/strong> <\/span>)<\/span>\n<span style=\"border-left: solid thick #FF0000;\">  {<\/span>\n<span style=\"border-left: solid thick #FF0000;\">    this.findShelf( callerControl.value() );<\/span>\n<span style=\"border-left: solid thick #FF0000;\">  }<\/span>\n}<\/pre>\n<p>I have highlighted the differences with\u00a0red indicators. \u00a0When a lookup is called from a reference group, we can get the reference group control from element.selectTarget(). \u00a0The value() property contains the reference record ID being looked up, in our case the shelf record ID. \u00a0We just pass this directly to findShelf().<\/p>\n<p>Open the form and open the lookup for one of the books to confirm that the correct shelf has been selected.<\/p>\n<p><a href=\"https:\/\/www.bakke.online\/wp-content\/uploads\/2017\/05\/eb_books_form_lookup_new.png\"><img loading=\"lazy\" decoding=\"async\" class=\"alignnone size-full wp-image-227\" src=\"https:\/\/www.bakke.online\/wp-content\/uploads\/2017\/05\/eb_books_form_lookup_new.png\" alt=\"\" width=\"442\" height=\"512\" \/><\/a><\/p>\n<h3>Wrapping up<\/h3>\n<p>That&#8217;s all for now. \u00a0I hope you have found this tutorial useful.<\/p>\n<p>There will be several ways the code can be made faster, more robust or more elegant, but I have tried to make it clear how this is all working and how it fits together. \u00a0Feel free to make whatever tweaks or improvements you want.<\/p>\n<p>An XPO with all the application objects disussed in this tutorial can be found\u00a0<a href=\"https:\/\/www.bakke.online\/wp-content\/uploads\/2017\/05\/SharedProject_EB_Library.zip\">here<\/a>.<\/p>\n","protected":false},"excerpt":{"rendered":"<p>This is something that keeps coming up on different projects, so I\u2019d like to share how I usually do this. \u00a0There are some examples out there which try to describe a very generic solution which can be used in almost any case. \u00a0However, such solutions very quickly become very complex. \u00a0To keep things simple, I &hellip; <a href=\"https:\/\/www.bakke.online\/index.php\/2017\/05\/02\/how-to-tree-lookups-in-dynamics-ax-reference-group-controls-part-4\/\" class=\"more-link\">Continue reading<span class=\"screen-reader-text\"> &#8220;How-to: Tree lookups in Dynamics AX reference group controls, part 4&#8221;<\/span><\/a><\/p>\n","protected":false},"author":1,"featured_media":0,"comment_status":"open","ping_status":"open","sticky":false,"template":"","format":"standard","meta":{"footnotes":""},"categories":[4,1],"tags":[2,3,5],"class_list":["post-223","post","type-post","status-publish","format-standard","hentry","category-dynamics-ax","category-uncategorized","tag-ax2012r3","tag-dynamics-ax","tag-user-interface"],"_links":{"self":[{"href":"https:\/\/www.bakke.online\/index.php\/wp-json\/wp\/v2\/posts\/223","targetHints":{"allow":["GET"]}}],"collection":[{"href":"https:\/\/www.bakke.online\/index.php\/wp-json\/wp\/v2\/posts"}],"about":[{"href":"https:\/\/www.bakke.online\/index.php\/wp-json\/wp\/v2\/types\/post"}],"author":[{"embeddable":true,"href":"https:\/\/www.bakke.online\/index.php\/wp-json\/wp\/v2\/users\/1"}],"replies":[{"embeddable":true,"href":"https:\/\/www.bakke.online\/index.php\/wp-json\/wp\/v2\/comments?post=223"}],"version-history":[{"count":0,"href":"https:\/\/www.bakke.online\/index.php\/wp-json\/wp\/v2\/posts\/223\/revisions"}],"wp:attachment":[{"href":"https:\/\/www.bakke.online\/index.php\/wp-json\/wp\/v2\/media?parent=223"}],"wp:term":[{"taxonomy":"category","embeddable":true,"href":"https:\/\/www.bakke.online\/index.php\/wp-json\/wp\/v2\/categories?post=223"},{"taxonomy":"post_tag","embeddable":true,"href":"https:\/\/www.bakke.online\/index.php\/wp-json\/wp\/v2\/tags?post=223"}],"curies":[{"name":"wp","href":"https:\/\/api.w.org\/{rel}","templated":true}]}}