# JavaScript API updates

**URL:** <https://community.datagrok.ai/t/javascript-api-updates/526>\
**Category:** Features\
**Tags:** datagrok, javascript\
**Created:** [March 15, 2021, 3:17pm UTC](https://community.datagrok.ai/t/javascript-api-updates/526 "2021-03-15T15:17:28Z")\
**Posts on this page:** 19\
**Page:** 1

<div class="post-metadata">

**Author:** ![dskatov](https://community.datagrok.ai/user_avatar/community.datagrok.ai/dskatov/32/71_2.png) [@dskatov](https://community.datagrok.ai/u/dskatov)\
**Post date:** [March 15, 2021, 3:17pm UTC](https://community.datagrok.ai/t/javascript-api-updates/526/1 "2021-03-15T15:17:28Z")

</div>

Let’s use this topic for reporting and discussing new Datagrok JavaScript API features.  
They become available on [http://dev.datagrok.ai/](http://dev.datagrok.ai/) at the time of the topic update.

---

<div class="post-metadata">

**Author:** ![dskatov](https://community.datagrok.ai/user_avatar/community.datagrok.ai/dskatov/32/71_2.png) [@dskatov](https://community.datagrok.ai/u/dskatov)\
**Post date:** [March 15, 2021, 3:29pm UTC](https://community.datagrok.ai/t/javascript-api-updates/526/4 "2021-03-15T15:29:48Z")

</div>

Pinned globally on March 15, 2021, 3:29pm UTC



---

<div class="post-metadata">

**Author:** ![dskatov](https://community.datagrok.ai/user_avatar/community.datagrok.ai/dskatov/32/71_2.png) [@dskatov](https://community.datagrok.ai/u/dskatov)\
**Post date:** [March 16, 2021, 11:56am UTC](https://community.datagrok.ai/t/javascript-api-updates/526/5 "2021-03-16T11:56:06Z")

</div>

We’ve added support for manipulating Datagrok `.temp` and `.tags` available for dataframes and columns. Now they can be manipulated just as one does with JavaScript’s `Map` or object properties (both API conventions are supported). For instance, here is how to iterate through the tags, print them to the browser’s console and then delete one key:

```auto
let demog = grok.data.demo.demog();
demog.tags.foo = 'bar';
for (const [key, value] of demog.tags)
  console.log(key, ':', value);
if ('foo' in demog.tags)
  delete demog.tags.foo;
grok.shell.info(`foo is present: ${demog.tags.has('foo')}`);

```

Try out the means to iterate and manipulate `.tags` and `.temp` collections in [this example on Datagrok](https://dev.datagrok.ai/js/samples/data-frame/metadata/metadata).

---

<div class="post-metadata">

**Author:** ![atuzhykov](https://community.datagrok.ai/letter_avatar_proxy/v4/letter/a/7feea3/32.png) [@atuzhykov](https://community.datagrok.ai/u/atuzhykov)\
**Post date:** [March 17, 2021, 10:12am UTC](https://community.datagrok.ai/t/javascript-api-updates/526/6 "2021-03-17T10:12:12Z")

</div>

We’ve added functionality to manipulate files using `grok.dapi.files.`  
At the moment you can use following list of file operations:

- write(file, blob)  
  
` await grok.dapi.files.write('Demo:TestJobs:Files:DemoFiles/testFile.dat', [0, 1, 2]);`

- writeAsText(file, data)  
  
` await grok.dapi.files.writeAsText('Demo:TestJobs:Files:DemoFiles/testFile.txt', 'testString');`

- readAsBytes(file)  
  
`await grok.dapi.files.readAsBytes('Demo:TestJobs:Files:DemoFiles/testFile.dat')`

- readAsText(file)  
  
`await grok.dapi.files.readAsText('Demo:TestJobs:Files:DemoFiles/testFile.txt')`

- exists(file)  
  
` await grok.dapi.files.exists('Demo:TestJobs:Files:DemoFiles/testFile.dat');`

- rename(file, newName)  
  
` await grok.dapi.files.rename('Demo:TestJobs:Files:DemoFiles/forRename.txt', 'renamed.txt');`

- list(file, recursive, searchPattern)

- move(files, newPath)  
  
` await grok.dapi.files.move(['Demo:TestJobs:Files:DemoFiles/testFile.txt'], 'geo');`

- delete(file)  
  
` await grok.dapi.files.delete('Demo:TestJobs:Files:DemoFiles/testFile.dat');`

Note, that these functions return promises you have to handle using `async/await` or `.then` chain.

You can take a look on JS API samples [here](https://github.com/datagrok-ai/public/blob/master/packages/ApiSamples/scripts/dapi/files.js) to be sure you use API correctly and launch your own as js scripts on the platform.

---

<div class="post-metadata">

**Author:** ![skalkin](https://community.datagrok.ai/user_avatar/community.datagrok.ai/skalkin/32/5_2.png) [@skalkin](https://community.datagrok.ai/u/skalkin)\
**Post date:** [March 27, 2021, 3:19am UTC](https://community.datagrok.ai/t/javascript-api-updates/526/7 "2021-03-27T03:19:53Z")

</div>

We have exposed the JS API for value matchers. See the following link for examples of all matchers (numerical, string, date, bool): [https://datagrok.ai/help/explore/data-search-patterns](https://datagrok.ai/help/explore/data-search-patterns)

Or play around with the following example: [https://dev.datagrok.ai/js/samples/data-frame/value-matching/value-matcher](https://dev.datagrok.ai/js/samples/data-frame/value-matching/value-matcher)

```
let matcher = DG.ValueMatcher.numerical('> 30');

grok.shell.info(matcher.operator); // '>'
grok.shell.info(matcher.match(40)); // true
grok.shell.info(matcher.validate(20)); // "> 30" does not match "20"
```

---

<div class="post-metadata">

**Author:** ![akuznetsov](https://community.datagrok.ai/user_avatar/community.datagrok.ai/akuznetsov/32/192_2.png) [@akuznetsov](https://community.datagrok.ai/u/akuznetsov)\
**Post date:** [April 9, 2021, 9:10pm UTC](https://community.datagrok.ai/t/javascript-api-updates/526/8 "2021-04-09T21:10:32Z")

</div>

We added an event subscription API for Grid column and rows resize. Datagrok will be sending events on resize with properties to identify if resize is still in progress or just ended (`ev.args.dragging`) and which column gets resized (`ev.args.column`).

Code example:

```
let grid = grok.shell.addTableView(grok.data.demo.demog()).grid;

grid.onRowsResized.subscribe((ev) => {
  let status = ev.args.dragging ? "dragging" : "done";
  grok.shell.info("Resizing row height: " + status);
});

grid.onColumnResized.subscribe((ev) => {
  let status = ev.args.dragging ? "dragging" : "done";
  grok.shell.info(`Resizing ${ev.args.column.name}: ` + status);
});

```

[[https://github.com/datagrok-ai/public/blob/master/packages/ApiSamples/scripts/grid/resize-events.js](https://github.com/datagrok-ai/public/blob/master/packages/ApiSamples/scripts/grid/resize-events.js)]

@dpetrov.gnf.org @andreas.gasser.novartis.com

---

<div class="post-metadata">

**Author:** ![skalkin](https://community.datagrok.ai/user_avatar/community.datagrok.ai/skalkin/32/5_2.png) [@skalkin](https://community.datagrok.ai/u/skalkin)\
**Post date:** [April 15, 2021, 11:16pm UTC](https://community.datagrok.ai/t/javascript-api-updates/526/9 "2021-04-15T23:16:41Z")

</div>

Today we are introducing an important new feature - the ability to provide custom value comparison function that is used for sorting the column. The following script demonstrates the concept, all that is needed is to set `column.valueComparer`:

```
// Providing custom comparer function

// Let's say we have a string column where values have some logical order
let column = DG.Column.fromList(DG.TYPE.STRING, 'months', ['Feb', 'Jan', 'May', 'Mar']);

// Define and set a custom value comparer that is used for sorting later
let months = { Jan: 1, Feb: 2, Mar: 3, Apr: 4, May: 5 };
column.valueComparer = (s1, s2) => months[s1] - months[s2];

// It is possible to get the sorted order if needed
let order = column.getSortedOrder();
grok.shell.info(Array.from(order).map((i) => column.get(i)).join(', '));

// Or, simply double-click on the header to sort it visually
grok.shell.addTableView(DG.DataFrame.fromColumns([column]));

```

Once a value comparer is defined for a column, it gets used by all visualizations, and for other purposes such as aggregation as well. Check out the screenshot below (a result of running the script above) and note the proper sorted order on all charts:

 ![image](https://community.datagrok.ai/uploads/default/original/1X/307708ea46af1153c15a0e99363587228883b9f7.png)

@nico.pulver.novartis.com, @nikolaus.stiefl.novartis.com, @ptosco, @timothy.danford.novartis.com - I believe you have plenty of applications for that feature 🙂

---

<div class="post-metadata">

**Author:** ![nico.pulver.novartis.com](https://community.datagrok.ai/letter_avatar_proxy/v4/letter/n/76d3ee/32.png) [@nico.pulver.novartis.com](https://community.datagrok.ai/u/nico.pulver.novartis.com)\
**Post date:** [April 19, 2021, 8:29am UTC](https://community.datagrok.ai/t/javascript-api-updates/526/10 "2021-04-19T08:29:17Z")

</div>

That’s really cool, Andrew, thanks a lot!  
We will need that to support custom sorting by the user’s list of favorite compound ids.

---

<div class="post-metadata">

**Author:** ![kdoncov](https://community.datagrok.ai/letter_avatar_proxy/v4/letter/k/b3f665/32.png) [@kdoncov](https://community.datagrok.ai/u/kdoncov)\
**Post date:** [May 28, 2021, 5:18pm UTC](https://community.datagrok.ai/t/javascript-api-updates/526/11 "2021-05-28T17:18:10Z")

</div>

We have currently added several scatter plot customizations:

- method `hitTest` for row hit testing using canvas coords;
- method `zoom` for zooming using world coords;
- method `worldToScreen` for converting world coords to screen coords;
- getters `viewBox`, `xAxisBox`, `yAxisBox` for view box and axes rectangles;
- property `viewport` for the current viewport rectangle;
- events `onZoomed`, `onViewportChanged`, `onAfterDrawScene` for the corresponding scatter plot events;

---

<div class="post-metadata">

**Author:** ![skalkin](https://community.datagrok.ai/user_avatar/community.datagrok.ai/skalkin/32/5_2.png) [@skalkin](https://community.datagrok.ai/u/skalkin)\
**Post date:** [July 25, 2021, 6:59pm UTC](https://community.datagrok.ai/t/javascript-api-updates/526/12 "2021-07-25T18:59:12Z")

</div>

onMetadataChanged now fires MapChangeArgs events, allowing for a granular event handling. The following example intercepts the change of the column’s conditional color-coding settings:

```
demog.onMetadataChanged
  .pipe(rxjs.operators.filter(data => data.args.key === DG.TAGS.COLOR_CODING_CONDITIONAL))
  .subscribe((data) => info(`${data.args.change} - ${data.args.key} - ${data.args.value}`));

```

Here is the MapChangeArgs interface:

```
export interface MapChangeArgs<K, V> {
  sender: any;
  change: string;
  key: K;
  value: V;
}
```

---

<div class="post-metadata">

**Author:** ![aydar.akhmetov](https://community.datagrok.ai/user_avatar/community.datagrok.ai/aydar.akhmetov/32/221_2.png) [@aydar.akhmetov](https://community.datagrok.ai/u/aydar.akhmetov)\
**Post date:** [July 30, 2021, 5:53pm UTC](https://community.datagrok.ai/t/javascript-api-updates/526/13 "2021-07-30T17:53:34Z")

</div>

We’ve added support for creating drag-n-drop objects.  
Any object can be made draggable. And any object can be made a receiver of other objects. Some objects have built-in drag-n-drop support, such as table columns.  
In the example, we are making a drag-and-droppable image.

```javascript
let df = DG.DataFrame.fromColumns([
  DG.Column.fromList(DG.TYPE.STRING,
    'Character', ['Alf', 'Kate', 'Willie']),
  DG.Column.fromList(DG.TYPE.INT, 
    'Age', [229, 45, 42]),
  DG.Column.fromList(DG.TYPE.STRING,
    'Actor', ['Paul Fusco', 'Anne Schedeen', 'Max Wright'])
]);

let control = ui.searchInput('', 'Drag column header or image here...');

let grid = DG.Viewer.grid(df);

let image = ui.image(
  'https://datagrok.ai/img/heinlein.jpg',
  200, 200,
  {target: 'https://datagrok.ai', tooltipMsg: 'Drag Heinlein to Input field'}
);

// Allow dragging and dropping objects into the search field:
ui.makeDroppable(control.input, {
  acceptDrop: (o) => true, // Allow to drag anything into the field
  doDrop: (o, _) => { // Let's check what fell into the input field
    if (o instanceof DG.Column)
      control.value = o.name.toUpperCase() + ' was dropped';
    else if (o instanceof HTMLDivElement)
      control.value = o.style.backgroundImage;
  }
});

// Let's grab and drag the object (image):
ui.makeDraggable(image, {
  getDragObject: () => image, 
  getDragCaption: () => 'You are dragging Heinlein!'
});

ui.dialog()
  .add(control)
  .add(grid)
  .add(image)
  .show();

```

---

<div class="post-metadata">

**Author:** ![skalkin](https://community.datagrok.ai/user_avatar/community.datagrok.ai/skalkin/32/5_2.png) [@skalkin](https://community.datagrok.ai/u/skalkin)\
**Post date:** [August 1, 2021, 7:41pm UTC](https://community.datagrok.ai/t/javascript-api-updates/526/14 "2021-08-01T19:41:50Z")

</div>

Use the following functions to get the color of the cell (note that the parameter is a DataFrameCell, not GridCell)

```auto
DG.Color.getCellColorHtml(cell: Cell): string
DG.Color.getCellColor(cell: Cell): number

```

Working example: [https://dev.datagrok.ai/js/samples/grid/color-coding/get-cell-color](https://dev.datagrok.ai/js/samples/grid/color-coding/get-cell-color)

---

<div class="post-metadata">

**Author:** ![skalkin](https://community.datagrok.ai/user_avatar/community.datagrok.ai/skalkin/32/5_2.png) [@skalkin](https://community.datagrok.ai/u/skalkin)\
**Post date:** [March 8, 2022, 5:03pm UTC](https://community.datagrok.ai/t/javascript-api-updates/526/15 "2022-03-08T17:03:14Z")

</div>

Unpinned on March 8, 2022, 5:03pm UTC



---

<div class="post-metadata">

**Author:** ![skalkin](https://community.datagrok.ai/user_avatar/community.datagrok.ai/skalkin/32/5_2.png) [@skalkin](https://community.datagrok.ai/u/skalkin)\
**Post date:** [March 23, 2022, 12:11pm UTC](https://community.datagrok.ai/t/javascript-api-updates/526/16 "2022-03-23T12:11:42Z")

</div>

HTML cells could easily be rendered now by setting column’s renderer to `html`:

![image](https://community.datagrok.ai/uploads/default/original/1X/480fc5a48d23a1dde5264f62c35d3b9c21c4fa68.png)

Script: [https://github.com/datagrok-ai/public/blob/master/packages/ApiSamples/scripts/grid/html-cells/html-table-cells.js](https://github.com/datagrok-ai/public/blob/master/packages/ApiSamples/scripts/grid/html-cells/html-table-cells.js)

---

<div class="post-metadata">

**Author:** ![skalkin](https://community.datagrok.ai/user_avatar/community.datagrok.ai/skalkin/32/5_2.png) [@skalkin](https://community.datagrok.ai/u/skalkin)\
**Post date:** [March 24, 2022, 8:01pm UTC](https://community.datagrok.ai/t/javascript-api-updates/526/17 "2022-03-24T20:01:23Z")

</div>

Now you can retrieve and reuse grid cell renderers like that:

```auto
// Reusing core grid renderers

let view = grok.shell.addTableView(grok.data.demo.molecules());
view.dataFrame.col('age').colors.setLinear();
let canvas = ui.canvas(300, 200);

view.grid.onCurrentCellChanged.subscribe((gridCell) =>
  gridCell.renderer.render(canvas.getContext('2d'), 20, 20, 200, 100, gridCell, gridCell.style));

ui.dialog()
  .add('Click on a cell to render it in the canvas below')
  .add(canvas)
  .show();

```

![image](https://community.datagrok.ai/uploads/default/original/1X/70b027205788912867b3608046bbe5e0ebd57a98.png)

---

<div class="post-metadata">

**Author:** ![dkryvchuk](https://community.datagrok.ai/letter_avatar_proxy/v4/letter/d/d9b06d/32.png) [@dkryvchuk](https://community.datagrok.ai/u/dkryvchuk)\
**Post date:** [May 12, 2022, 5:11pm UTC](https://community.datagrok.ai/t/javascript-api-updates/526/18 "2022-05-12T17:11:04Z")

</div>

A new column type that stores binary data (UInt8Array) in cell has been added. Here’s how you would create such a column and set a 100-bytes array in the first row:

```

  const bytesCol = DG.Column.fromType(DG.COLUMN_TYPE.BYTE_ARRAY, 'bytes', 3);
  bytesCol.set(0, new UInt8Array(100));
 
```

When combined with semantic types, this feature allows storing and handling of arbitrary data types. For instance, this is used for rendering embedded images, check this out: [link to image renderer](https://github.com/datagrok-ai/public/blob/master/packages/PowerGrid/src/cell-types/binary-image-cell-renderer.ts)

---

<div class="post-metadata">

**Author:** ![skalkin](https://community.datagrok.ai/user_avatar/community.datagrok.ai/skalkin/32/5_2.png) [@skalkin](https://community.datagrok.ai/u/skalkin)\
**Post date:** [June 3, 2022, 6:47pm UTC](https://community.datagrok.ai/t/javascript-api-updates/526/19 "2022-06-03T18:47:06Z")

</div>

Set the `friendlyName` tag to change the way a column shows up in the UI (the real name stays the same)

![image](https://community.datagrok.ai/uploads/default/original/1X/5f6ba3f958690937c06c0f2bc660a34010c97220.png)

---

<div class="post-metadata">

**Author:** ![skalkin](https://community.datagrok.ai/user_avatar/community.datagrok.ai/skalkin/32/5_2.png) [@skalkin](https://community.datagrok.ai/u/skalkin)\
**Post date:** [December 23, 2022, 8:51pm UTC](https://community.datagrok.ai/t/javascript-api-updates/526/20 "2022-12-23T20:51:58Z")

</div>

Now, you can set default viewer settings for the specific dataframe:

```auto
let df = grok.data.demo.demog();
let defaultScatterPlotSettings = {
  xColumnName: 'height',
  yColumnName: 'weight',
  sizeColumnName: 'age',
  colorColumnName: 'race',
}

// now, all newly created viewers attached to df will inherit the specified settings:
df.tags['.Viewer Template: ' + DG.VIEWER.SCATTER_PLOT] = JSON.stringify(defaultScatterPlotSettings);
df.tags['.Viewer Template: ' + DG.VIEWER.HISTOGRAM] = JSON.stringify({valueColumnName: 'height'});

let view = grok.shell.addTableView(df);
view.scatterPlot();
view.histogram();

```

 ![image](https://community.datagrok.ai/uploads/default/original/1X/01883878c87eb6184de8c77bce24b976ef769a6f.png)

---

<div class="post-metadata">

**Author:** ![donufriienko](https://community.datagrok.ai/user_avatar/community.datagrok.ai/donufriienko/32/87_2.png) [@donufriienko](https://community.datagrok.ai/u/donufriienko)\
**Post date:** [April 7, 2023, 9:44am UTC](https://community.datagrok.ai/t/javascript-api-updates/526/21 "2023-04-07T09:44:19Z")

</div>

We’ve introduced a new feature for application developers. Now you can place hints for users in a form of indicators, popups, as well as describe a series of visual components in the wizard.

See examples:

1. [https://dev.datagrok.ai/js/samples/ux/Interactivity/hints](https://dev.datagrok.ai/js/samples/ux/Interactivity/hints)

2. [https://dev.datagrok.ai/js/samples/ux/Interactivity/wizard-hints](https://dev.datagrok.ai/js/samples/ux/Interactivity/wizard-hints)

 ![wizard](https://community.datagrok.ai/uploads/default/original/1X/84603abda3e9f950e153cb74f47c23316308d724.gif)
