The NExS embedded API

The NExS Embedded App Concept

NExS apps are web applications that are designed and built from spreadsheets.  They may be created from Excel, or from any spreadsheet editor (e.g., Google Sheets) that can export to the .xlsx file format.  NExS apps are created by uploading your spreadsheet to the NExS platform, which translates the contents of the spreadsheet into two components:

  • A front end HTML5 page that works with any modern browser (including mobile devices), and

  • A back end web service that performs the calculations defined by the formulas in your spreadsheet.

The net effect is that you can create a complete interactive web application that can be used stand-alone or embedded in a web page with no coding, using only your knowledge of how to build spreadsheets.

A NExS app is composed of one or more views.  A view is simply a range of cells from your spreadsheet (e.g., Sheet1!a1:g17).  The view may be an entire worksheet, or a subset.  (NOTE: any spreadsheet cells which are not included in a view are available for back end calculations, but are not exposed to the user.)

Within each view, selected cells may be designated as editable.  An editable cell’s value may be changed by the app user.  Editing a cell will trigger a back end calculations.  Any cells within the views whose values change as a result of the back end calculation will be automatically updated as a result.  Think of the editable cells as inputs to your web app, and the calculated values as outputs.

The NExS Embedded API is a lightweight javascript library which allows interaction with a NExS app that is embedded in your web page.  It is automatically loaded whenever you embed an app in your page using the embed code provided in the app’s management console.  Using the API, you can:

  • Read the values (but not formulas) of any cells in your app’s views.

  • Write values to the editable (input) cells of your app’s views.

  • Control which view is visible to the users of your page (for apps with multiple views).

  • Link HTML elements on your web page to your NExS app

    • Link <input> elements in your web page to editable cells.

    • Link <span> elements in your page to cell values.

    • Link a <select> element in your page to serve as a view controller.

The NEXS Object

When you embed a NExS app in your page, a top-level object named NEXS (note all caps) is created.  All interaction with NExS apps embedded on your page is via the NExS object.  The API exposes a set of chainable functions and objects to interact with your apps.  Here is a summary:

  • NEXS.app() selects an embedded app on your page.  The function argument is either a number or a string.  If a number, it is the zero-based index of the app within your page.  If a string, it selects the app by name.  For example, NEXS.app(0) selects the first app embedded in the page, and NEXS.app("My App") selects the app named “My App”.  Assuming that “My App” is the first app embedded in the page, then NEXS.app(0) and NEXS.app("My App") are equivalent.

  • NEXS.app().view() selects a view within the specified app.  Like NEXS.app(), views may be selected by index within the app, or by name.  NEXS.app(0).view(0) selects the first view of the first app embedded on the page, and NEXS.app(0).view("My First View") selects the view named “My First View” from the first app on the page.

  • NEXS.app().view().cell() selects a cell within a view and returns its contents.  Cells are selected by reference (e.g., “H1” references the spreadsheet cell in row 1 of column H of the worksheet associated with the selected view), or by name.  For example if you have named cell Sheet1!B17 as “foobar” in your spreadsheet, and NEXS.app(0).view(1) contains that cell, it can be referenced as either NEXS.app(0).view(1).cell("B17") or as NEXS.app(0).view(1).cell("foobar").

  • NEXS.app().view().setInputs() provides a programmatic interface to put data in editable cells.  The function takes an array of cell, value pairs as inputs.  For example, suppose cells B17 and C17 are editable cells in the view named “My View” on the first embedded app and we wish to put the value 1.25 in B17 and “gallons” in C17.  This would be accomplished by calling NEXS.app(0).view("My View").setInputs(["B17", 1.25, "C17", "gallons"]).  (Note the square brackets to denote the array.)  Storing values in editable cells triggers a recalculation, which will in turn update any cells with dependent formulas on all views.

  • NEXS.app().view().setInput(cell, value)is a convenience shorthand for setting a single cell value and recalculating.

  • NEXS.app().view().queueInputs() is exactly the same as NEXS.app().view().setInputs(), except that recalculation is not automatic.  The purpose is to allow multiple input values on multiple views to be set, deferring recalculation until NEXS.recalc() is called.  Since each recalculation requires a round trip to the server, this method significantly increases efficiency when setting inputs on multiple views.

  • NEXS.app().recalc() will send all queued inputs to the server, recalculate, and return any updates as a result of the recalculation.

  • NEXS.app().setView() serves as a program-controlled view selector.  If no argument is present, setView() returns the index of the currently displayed view.  Similar to the view() function, the argument may be a zero-based index or the name of the view to display.  If the argument does not select a valid view, the current view does not change and its index is returned.

Please note that the API methods described above are not available until app initialization is complete.  This is managed by listening for a “nexsappinit” event (see the Event section below).  For example, this code added to your HTML document won’t work:

  <script>
    console.log(NEXS.app(0).view(0).cell("D4").data);
  </script>

But this will:

  <script>
    document.addEventListener("nexsappinit", function (e) {
      console.log(NEXS.app(0).view(0).cell("D4").data);
    });
  </script>

Shorthand syntax

Simple applications of NExS often involve a single app with a single view embedded on a page.  For convenience, a shorthand syntax is provided for all of the API functions listed above.  Any reference to a resource prefixed by NEXS.app(0), for example,  NEXS.app(0).view(1), can be abbreviated as NEXS.view(1).  Similarly, any reference to a resource prefixed by NEXS.app().view(0) can be abbreviated as NEXS.app().  The abbreviations can be combined.  In other words, NEXS.cell("B17") is equivalent to NEXS.app(0).view(0).cell("B17").

Extended cell reference syntax

Cells in embedded apps can also be accessed using the following extended cell referencing syntax:

    [appRef]viewRef!cellRef

Where

  • appRef is the app name, or the zero-based index for the embedded app within the page (the first embedded app’s index is 0, the second is 1, and so on).

  • viewRef is the view name, or the zero-based index of view within the app (similar to above).

  • cellRef is a standard cell address; e.g., “B7”, or a cell name; e.g., “Input_1”.

  • If the appRef and/or viewRef components are omitted, they are assumed to be 0.  For example, the address above, “B7” is equivalent to “[0]0!B7”.

If you wanted to reference cell B7 on NEXS.app(1).view(2), you would specify the address “[1]2!B7”.  If the second embedded app on the page is named “My App” and the third view on “My App” is named “Dashboard”, then “[1]2!B7” is equivalent to “[My App]Dashboard!B7”.

Using extended cell referencing syntax, NEXS.cell("[appRef]viewRef!cellRef") is exactly equivalent to NEXS.app("appRef").view("viewRef").cell("cellRef").

The cell object

The object returned by NEXS.app(0).view(0).cell("B17") provides information about the cell’s contents, and may look like this:

{data: 64800, datatype: "numeric", text: "$64,800 ", editable: false}

This says that the cell contains a number, 64800, which is formatted display as $64,800, and the cell is not editable.  Cells which contain text string values look like this:

{data: "Premium", datatype: "string", text: "Premium", editable: true}

Note that the data property of the cell object is the same as the text property because the datatype is “string”.  Also note that the referenced cell is editable in this example.  Finally, note that there is no formula property in either of these examples.  Formulas are considered private and not exposed in the client app.

Hidden views

While the concept of a hidden view may sound like an oxymoron, it’s a valuable feature for designing certain classes of apps.  Suppose you want to have inputs to your app which are to be set programmatically via NEXS.app().view().setInputs().   Recall that the setInputs() function takes an array of editable cell, value pairs.  What if we don’t want the user to have direct access to those editable cells?  That’s when a hidden view, aka invisible view, is useful.  A hidden view is never visible on the app, and can only be referenced by name.  A view may be designated as “hidden” or “invisible” when the app is created.  You can access the cells in a hidden view only via the API.  For example, if your app has a hidden view named “My Hidden View” composed of the range A1:A15 on Sheet2, and all the cells are editable, you can set the value of cell A1 by calling

  NEXS.app(0).view("My Hidden View").setInputs(["a1", 1.2])

It is actually possible to create a NExS app with nothing but hidden views, in which case you would design your own user interface in HTML and use the NEXS API to interact with it.  This gives the app designer complete creative freedom.  The section below on the declarative API provides a convenient mechanism to support this design strategy, if desired.

Events

The NExS embedded API makes three events available that are accessed by adding an event listener to the window.  The object passed to the event handlers contains a “detail” property which contains data about the event.  All events are passed the property  detail.appIndex which is the index of the app associated with the event.

  • The “nexsappinit” event fires when the app is first initialized and all of the interfaces described herein are available for use.

  • The “nexsappupdated” event fires whenever the cells of the app have been updated.

  • The “nexsviewchanged” event fires whenever a different view is selected on the app.

  • The “nextbuttonclick” event fires whenever a button is clicked on the app.  (See the Button keyword in the NExS App Configuration documentation.)  The code associated with the button click may manipulate the app, or execute any valid javascript code.  In addition to the appIndex property, additional properties exposed via the event.detail object are:

    • view: the name of the view containing the button

    • cell: the cell address of the button

    • text: the text displayed on the button

    • datatype: the datatype of the button’s cell (“string”, “numeric” or “error”)

    • data: the value of the button’s cell (a text string, number or error message)

    • extra: user-defined data element (default is null)

Example:

  <script>
    document.addEventListener("nexsbuttonclick",
      function(e) {
        alert("button clicked: " +
              " view = " + e.detail.view +
              " cell = " + e.detail.cell +
              " text = " + e.detail.text
        );
      }
    );
  </script>

The NExS Declarative API

The NExS Declarative API provides a mechanism for easily linking HTML elements in your web page to cells within your NExS app without any coding.  For example, you can link an <input> element to an editable cell.  Any time the value of the <input> element is changed (e.g., entering a new value, that value will be automatically sent to the linked cell.  The connection is two-way, which means that if you edit the cell within the NExS app, the linked <input> element will update accordingly.  To connect an <input> element to a cell of an embedded NExS app, simply add the class name nexs__input and an attribute data-nexs-cell-addr to the <input> tag.  The data-nexs-cell-addr attribute’s value is the address of the editable cell, eg., B7, that the <input> element is linked to.  For example:

  <input class="nexs__input" data-nexs-cell-addr="B7">

Will link the input element to cell B7 of the first view of the first embedded app.  What if you want to link to a different view, or a different app?  The data-nexs-cell-addr attribute accepts the full extended cell reference syntax described above.

Similar to <input> linking, the values of NExS cells can be linked to <span> elements to display on your page.  In this case, apply the class name nexs__output_formatted to link the cell’s formatted value to the <span>.  If you want the unformatted value, use class nexs__output_raw.  Suppose cell B5 contains the value 1.232 and is formatted as currency with 2 decimal places.  A span with class nexs__output_formatted will display “$1.23” (the text property of the Cell object) on your page, while a span with class nexs__output_raw will display “1.232” (the data property).

An additional feature of the declarative API is to create a view selector.  A <select> element with the class nexs__viewselect will create a drop-down list of views on your page.  Selecting a view from the list switches the display to that view.  By default, the view selector is attached to NEXS.app(0).  If you with to attach to another app, add the attribute data-nexs-app to the <select> tag.  For example, the following will create a view selector for NEXS.app(1):

  <select class="nexs__viewselect" data-nexs-app="1"></select>

A helpful demonstration of the NExS Declarative API is found here.