{"id":560,"date":"2017-02-20T00:19:53","date_gmt":"2017-02-20T05:19:53","guid":{"rendered":"http:\/\/hardlikesoftware.com\/weblog\/?p=560"},"modified":"2017-03-31T10:33:58","modified_gmt":"2017-03-31T15:33:58","slug":"how-to-hack-apex-interactive-grid-part-3","status":"publish","type":"post","link":"https:\/\/hardlikesoftware.com\/weblog\/2017\/02\/20\/how-to-hack-apex-interactive-grid-part-3\/","title":{"rendered":"How to hack APEX Interactive Grid Part 3"},"content":{"rendered":"<p>If you haven&#8217;t read parts <a href='http:\/\/hardlikesoftware.com\/weblog\/2017\/01\/18\/how-to-hack-apex-interactive-grid-part-1\/'>one<\/a> and <a href='http:\/\/hardlikesoftware.com\/weblog\/2017\/01\/24\/how-to-hack-apex-interactive-grid-part-2\/'>two<\/a> yet you probably should before proceeding with this one. They covered some basics, configuration and toolbar and menu customization. In part 3 I&#8217;ll explain how to control and interact with Interactive Grid (IG) using JavaScript. As was already mentioned in parts 1 and 2 this is aimed at people with at least intermediate level experience with APEX and JavaScript Also most of the APIs are not documented or supported. <\/p>\n<p>[Update 5.1.1 28-Mar-2017] This article has been updated to reflect patch release 5.1.1<\/p>\n<p><!--more--><\/p>\n<h2>Control<\/h2>\n<p>There are a few general ways to control and interact with IG from JavaScript code. One simple, common action that can be done to an IG is refresh the data. This is a documented and supported API.<\/p>\n<pre style=\"white-space:pre;word-wrap:normal\"><code>apex.region(\"regionStaticID\").refresh();\r\n<\/code><\/pre>\n<p>This same code will work to refresh any region that supports being refreshed (just supply the correct Static ID). This is the new official 5.1 way to refresh a region. There is also an equivalent dynamic action called <code>Refresh<\/code> (same as in previous releases but internally uses the <code>apex.region<\/code> API). A difference compared to other APEX components is that with IG the server returns just the data as JSON. Other components such as Interactive Reports return markup that includes more than just the data; for example the toolbar. This difference may only be of academic interest, but should not be a surprise once you understand the basic <a href='http:\/\/hardlikesoftware.com\/weblog\/2016\/06\/08\/interactive-grid-under-the-hood\/'>architecture of IG<\/a>. Another differences is that if the IG is editable and has any changes then the user is prompted to confirm the refresh so that they don&#8217;t loose changes by accident. <\/p>\n<p>If you don&#8217;t want to prompt the user you must explicitly clear the model changes first. The user should not be surprised about loosing changes. For example the following JavaScript code could be on a dynamic action on a button labeled &#8220;Cancel Changes&#8221;. (This is getting a bit ahead of ourselves by using a model API.)<\/p>\n<p>[Update 5.1.1] The following code was updated for 5.1.1 to use getCurrentView method.<\/p>\n<pre style=\"white-space:pre;word-wrap:normal\"><code>var ig$ = apex.region(\"emp\").widget(),\r\n    view = ig$.interactiveGrid(\"getCurrentView\");\r\n\r\nif ( view.internalIdentifier === \"grid\" ) { \/\/ only grid supports editing\r\n    view.model.clearChanges();\r\n}\r\napex.region(\"emp\").refresh();\r\n<\/code><\/pre>\n<p>Another supported API on the region interface is focus. You can give focus to an IG with the following:<\/p>\n<pre style=\"white-space:pre;word-wrap:normal\"><code>apex.region(\"regionStaticID\").focus();\r\n<\/code><\/pre>\n<p>At this time there isn&#8217;t a corresponding DA action (Set Focus works for items but not regions). <\/p>\n<h2>Actions<\/h2>\n<p>The next easiest programmatic thing to do is invoke any of the menu or toolbar actions. In part 2 an example was given of defining an action and hooking it up to a toolbar button but little was said of what can be done with an action. (You should consult the doc comments in the <code>libraries\/apex\/actions.js<\/code> file for full details on the <code>apex.actions<\/code> API.) If you know the name of an action then you can run or execute the action with the invoke method. So the next logical question is &#8220;what are all the IG action names?&#8221; By now you probably know better than to ask where they are documented, right? <\/p>\n<p>The following code typed into the browser console window of an APEX page with an IG on it will print out a nice list of action names along with the label and for radio group actions the choice value.<\/p>\n<pre style=\"white-space:pre;word-wrap:normal\"><code>apex.region(\"emp\").widget().interactiveGrid(\"getActions\").list().forEach(function(a) { console.log(\"Action Label: \" + a.label + \", Name: \" + a.name + (a.choice !== undefined ? \", Choice: \" + a.choice : \"\") ); });\r\n<\/code><\/pre>\n<p>You should be able to match the action name with what it does by the label which matches the toolbar button label or tooltip or menu item label. In the case of a toggle action the menu item label may not include the word Toggle. In the case of radio group actions the label may be on the tooltip or on a sub-menu label.<\/p>\n<p>For example, the following code will open the IG Sort dialog just as if the user had clicked Actions menu, Data sub-menu and then Sort.<\/p>\n<pre style=\"white-space:pre;word-wrap:normal\"><code>apex.region(\"emp\").widget().interactiveGrid(\"getActions\").invoke(\"show-sort-dialog\");\r\n<\/code><\/pre>\n<p>The <code>getActions<\/code> method of the interactiveGrid widget returns the <code>apex.actions<\/code> context associated with the IG. Each IG has its own actions context. The action context is shared with all the sub widgets such as grid and recordView (Single Row View).<\/p>\n<p>There are 3 kinds of actions. The most obvious is just known as an action. These are generally associated with a button or menu item. It has an <code>action<\/code> method which is a function that defines what it does when invoked. The above IG <code>show-sort-dialog<\/code> action is an example.<\/p>\n<p>Toggle is another kind of action. These actions are generally associated with a checkbox, toggle button, toggle toolbar control, or toggle menu item. Rather than an <code>action<\/code> method it has <code>get<\/code> and <code>set<\/code> methods that set or get a Boolean value. The IG action <code>edit<\/code> is an example of a toggle action. To find out if the IG is currently in edit mode use this code:<\/p>\n<pre style=\"white-space:pre;word-wrap:normal\"><code>apex.region(\"emp\").widget().interactiveGrid(\"getActions\").get(\"edit\"); \/\/ returns true or false\r\n<\/code><\/pre>\n<p>To turn edit mode on:<\/p>\n<pre style=\"white-space:pre;word-wrap:normal\"><code>apex.region(\"emp\").widget().interactiveGrid(\"getActions\").set(\"edit\", true);\r\n<\/code><\/pre>\n<p>To turn edit mode off:<\/p>\n<pre style=\"white-space:pre;word-wrap:normal\"><code>apex.region(\"emp\").widget().interactiveGrid(\"getActions\").set(\"edit\", false);\r\n<\/code><\/pre>\n<p>The last kind of action is a radio group or choice action. It lets you select one value from a list of choices. These actions are generally associated with radio inputs, select lists, radio group menu items or radio group toolbar controls. These also have <code>get<\/code> and <code>set<\/code> methods. They also have an array of choices. The IG action <code>change-view<\/code> is an example of a radio group action. To find out what view is currently selected use this code:<\/p>\n<pre style=\"white-space:pre;word-wrap:normal\"><code>apex.region(\"emp\").widget().interactiveGrid(\"getActions\").get(\"change-view\");\r\n<\/code><\/pre>\n<p>To change the current view to chart view (assuming it is defined) use this code:<\/p>\n<pre style=\"white-space:pre;word-wrap:normal\"><code>apex.region(\"emp\").widget().interactiveGrid(\"getActions\").set(\"change-view\", \"chart\");\r\n<\/code><\/pre>\n<p>To find out the available choices use this code and look through the returned array:<\/p>\n<pre style=\"white-space:pre;word-wrap:normal\"><code>apex.region(\"emp\").widget().interactiveGrid(\"getActions\").lookup(\"change-view\").choices\r\n<\/code><\/pre>\n<p>Another example is saving the current grid. For this you can use the <code>save<\/code> action as follows:<\/p>\n<pre style=\"white-space:pre;word-wrap:normal\"><code>apex.region(\"emp\").widget().interactiveGrid(\"getActions\").invoke(\"save\");\r\n<\/code><\/pre>\n<p>This requires that the IG attribute Toolbar: Buttons Save is checked since it controls creation of both the button and the <code>save<\/code> action. You could use toolbar customization to remove just the Save button. <del datetime=\"2017-03-29T03:29:52+00:00\">Currently there is no easy reliable way to detect when the save has completed.<\/del> [Update 5.1.1] If you need to do anything after the save is complete you can handle the save event. Events are covered in the next part of this series.<\/p>\n<p>All the above information about actions applies to actions you create and add to the IG context as described in part 2. The examples in part 2 created actions to be invoked but you can also create toggle or radio group actions by implementing the set and get methods and for radio groups also defining the choices.<\/p>\n<h2>Widget Methods<\/h2>\n<p>If there isn&#8217;t a built-in IG action that does what you want there may be a way to accomplish it with JavaScript code calling methods on the <a href='http:\/\/hardlikesoftware.com\/weblog\/2016\/06\/08\/interactive-grid-under-the-hood\/'>various widgets<\/a> that make up IG. Many of the methods on the interactive grid widget itself are not very stable in 5.1. [Update 5.1.1] We have already seen <del datetime=\"2017-03-29T03:29:52+00:00\">all<\/del> many of the interactive grid widget methods that are useful right now. They are: <code>getActions<\/code>, <code>getViews<\/code>, <code>getCurrentView<\/code> and <code>getCurrentViewId<\/code>. [Update 5.1.1] Other IG widget methods are: <code>resize<\/code>, <code>refresh<\/code>, <code>gotoCell<\/code>, <code>getToolbar<\/code>, <code>getSelectedRecords<\/code>, <code>setSelectedRecords<\/code>, and <code>focus<\/code>. Refer to doc comments in the <code>libraries\/apex\/widget.interactiveGrid.js<\/code> source file for details on these.<\/p>\n<p>Each of the different views (grid, chart, icon, and detail) are implemented by a widget. You can drill down into the view widget by first getting at the IG view interface. Using code such as the following:<\/p>\n<pre style=\"white-space:pre;word-wrap:normal\"><code>apex.region(\"emp\").widget().interactiveGrid(\"getViews\", \"grid\");\r\n<\/code><\/pre>\n<p>Calling <code>getViews<\/code> with no argument returns an object containing all the currently defined views. Each property is the id of a view and the value is the view interface. So the following is equivalent to the previous statement as long as the view exists.<\/p>\n<pre style=\"white-space:pre;word-wrap:normal\"><code>apex.region(\"emp\").widget().interactiveGrid(\"getViews\").grid;\r\n<\/code><\/pre>\n<p>You should make sure the view exists before trying to use it. You can use the <code>getCurrentViewId<\/code> to get the id (<code>internalIdentifier<\/code>) of the current view. [Update 5.1.1] You can use <code>getCurrentView<\/code> to get the current view. This is shorter than getting the current view id and passing it in to the <code>getViews<\/code> method.<\/p>\n<p>The view interface has these useful properties:<\/p>\n<ul>\n<li>view$ &#8211; this is the jQuery object of the view element.<\/li>\n<li>model &#8211; this is the apex.model for the view.<\/li>\n<li>internalIdentifier &#8211; this is the id of the view. For example &#8220;chart&#8221;<\/li>\n<li>getSelectedRecords &#8211; this is a function that returns an array of the selected model records.<\/li>\n<li>singleRowView$ &#8211; this is only defined for the grid view it is the jQuery object for the Single Row View element which is managed by the recordView widget.<\/li>\n<li>rowActionMenu$ &#8211; [Update 5.1.1] this is only defined for the grid view. It is the jQuery object for the row actions menu.<\/li>\n<li>selActionMenu$ &#8211; [Update 5.1.1] this is only defined for the grid view. It is the jQuery object for the selection actions menu.<\/li>\n<\/ul>\n<p>An example using <code>getViews<\/code>, <code>getCurrentView<del datetime=\"2017-03-29T03:29:52+00:00\">Id<\/del><\/code> and the <code>model<\/code> property to clear changes in the model was given above.<\/p>\n<p>The grid view has a number of useful methods. Consult the doc comments in the file <code>libraries\/apex\/widget.grid.js<\/code> for details. Here is a simple example. Suppose you wanted to select all the rows (as if the select all checkbox was checked). The following code would do that assuming the static id for the IG region is emp and the IG is configured to allow multiple selection and select all.<\/p>\n<pre style=\"white-space:pre;word-wrap:normal\"><code>apex.region(\"emp\").widget().interactiveGrid(\"getViews\", \"grid\").view$.grid(\"selectAll\")\r\n<\/code><\/pre>\n<p>The chart view uses the Oracle JET <code>ojChart<\/code> widget. You can consult the <a href='http:\/\/www.oracle.com\/webfolder\/technetwork\/jet\/jsdocs\/oj.ojChart.html'>JET documentation<\/a> for details (note the link may point to a newer version of JET than APEX uses). The following example will change the chart orientation to horizontal.<\/p>\n<pre style=\"white-space:pre;word-wrap:normal\"><code>apex.region(\"emp\").widget().interactiveGrid(\"getViews\").chart.view$.ojChart(\"option\", {orientation: \"horizontal\"})\r\n<\/code><\/pre>\n<p>This assumes the IG Static Id is emp, the current view is chart and the chart type supports the orientation property (for example it is a bar chart). Changes directly to the view generally do not affect the IG report settings.<\/p>\n<p>That&#8217;s all there is to controlling the Interactive Grid region. The details are in learning about the available actions and widget methods. I&#8217;ve decided to add a forth part to this series to cover widget events and the data model layer; accessing, modifying, and listening to notifications.<\/p>\n","protected":false},"excerpt":{"rendered":"<p>If you haven&#8217;t read parts one and two yet you probably should before proceeding with this one. They covered some basics, configuration and toolbar and<\/p>\n<div class=\"more-link-wrapper\"><a class=\"more-link\" href=\"https:\/\/hardlikesoftware.com\/weblog\/2017\/02\/20\/how-to-hack-apex-interactive-grid-part-3\/\">Continue reading<span class=\"screen-reader-text\">How to hack APEX Interactive Grid Part 3<\/span><\/a><\/div>\n","protected":false},"author":1,"featured_media":0,"comment_status":"open","ping_status":"open","sticky":false,"template":"","format":"standard","meta":[],"categories":[18],"tags":[41,43,44],"_links":{"self":[{"href":"https:\/\/hardlikesoftware.com\/weblog\/wp-json\/wp\/v2\/posts\/560"}],"collection":[{"href":"https:\/\/hardlikesoftware.com\/weblog\/wp-json\/wp\/v2\/posts"}],"about":[{"href":"https:\/\/hardlikesoftware.com\/weblog\/wp-json\/wp\/v2\/types\/post"}],"author":[{"embeddable":true,"href":"https:\/\/hardlikesoftware.com\/weblog\/wp-json\/wp\/v2\/users\/1"}],"replies":[{"embeddable":true,"href":"https:\/\/hardlikesoftware.com\/weblog\/wp-json\/wp\/v2\/comments?post=560"}],"version-history":[{"count":13,"href":"https:\/\/hardlikesoftware.com\/weblog\/wp-json\/wp\/v2\/posts\/560\/revisions"}],"predecessor-version":[{"id":581,"href":"https:\/\/hardlikesoftware.com\/weblog\/wp-json\/wp\/v2\/posts\/560\/revisions\/581"}],"wp:attachment":[{"href":"https:\/\/hardlikesoftware.com\/weblog\/wp-json\/wp\/v2\/media?parent=560"}],"wp:term":[{"taxonomy":"category","embeddable":true,"href":"https:\/\/hardlikesoftware.com\/weblog\/wp-json\/wp\/v2\/categories?post=560"},{"taxonomy":"post_tag","embeddable":true,"href":"https:\/\/hardlikesoftware.com\/weblog\/wp-json\/wp\/v2\/tags?post=560"}],"curies":[{"name":"wp","href":"https:\/\/api.w.org\/{rel}","templated":true}]}}