Almost exactly three years ago, we enabled apps to be shared with others. From that point on, app authors were able to embed their shared apps in websites, but apps have until now been islands unto themselves, unable to communicate with the host page.
That changes with this release. We’re now introducing the
calcapp-iframe.js
JavaScript library, which can be used to extract values from apps you
embed.
We don’t expect most Calcapp authors to make direct use of this library. Using it, for the most part, requires traditional programming skills and part of Calcapp’s appeal, of course, is that we only require a familiarity with formulas and not traditional programming.
(There is one way to use the library without doing traditional programming, though. Our new auto-height feature only requires you to add a few attributes to your HTML markup to enable the feature. Behind the scenes, the JavaScript library is used.)
Most people making use of this library, at least initially, will be
programmers working to integrate the services their companies provide
with Calcapp. Indeed, that was our impetus for creating calcapp-iframe.js
— an
app author wanted to enable the app he created to talk to his hosted
payment page and he asked us to work together with his payment
provider. We learned what we had to make happen in order for them to
create their Calcapp integration and the result is this library.
The rest of this blog post is an in-depth technical description of how programmers can make use of this library. Don’t worry — we haven’t switched our focus to building a tool for traditional programmers! We’ll be back soon with new features geared completely towards no-code app development.
Using the library from JavaScript
The library must be loaded from https://connect.calcapp.net/calcapp-iframe.js
or from https://connect.calcapp.net/calcapp-iframe.min.js
.
(The latter address if for the minified version, which is smaller and
downloads faster but does not include any documentation.) Please
don’t self-host the library; we may make changes to it from time to
time as Calcapp evolves. Add the defer
attribute to the
script tag you use to load the library to prevent it from slowing
down your page as it loads.
A number of features are used which are not necessarily supported by older browsers, notably Internet Explorer. To make this library work for users on older browsers, a number of polyfills need to be loaded. (A polyfill is an implementation of a browser feature in JavaScript, often with fewer features or worse performance than the corresponding feature offered natively in the browser.)
To generate markup including appropriate polyfills, use the new embed tab of the window which appears when you share an app and click Support Internet Explorer:
This library sets the calcappIframe
property
of the window
object to an
instance which serves as the entry point to this library. Host pages
can use this object to retrieve values from the host app and to ask
this library to automatically manage the dimensions of iframe
elements hosting
apps written with Calcapp.
For instance, to print the value of field named Field1
, part of a panel
named MainPanel
, to your
JavaScript console, use this code:
calcappIframe.getValue("MainPanel", "Field1").then(function(value) {
console.log("Value: " + value);
}).catch(function(error) {
console.error("Error: " + error);
});
These functions are part of the calcappIframe
object:
- calcappIframe.getValue()
- calcappIframe.getValues()
- calcappIframe.subscribeToNewHeight()
- calcappIframe.manageHeight()
calcappIframe.getValue
Returns a promise which is resolved with a value from an app built
with Calcapp and hosted by an iframe
element, or is
rejected with an error message if there is a problem. To print the
value of field named Field1
, part of a panel
named MainPanel
, to your
JavaScript console, use this code:
calcappIframe.getValue("MainPanel", "Field1").then(function(value) {
console.log("Value: " + value);
}).catch(function(error) {
console.error("Error: " + error);
});
Use the getValues function instead of this function if multiple values need to be retrieved.
Calculations, variables and properties
Values in an app built with Calcapp are stored by
properties, which belong to either variables or
calculations. Fields, text boxes, groups, buttons and list
panel items are all variables. Fields offer a default property which
holds the field value, but also properties such as visible
(determining
whether the field is visible), label
(the label of the
field), initialValue
(the value
displayed initially for the field), formattedValue
(the
field value formatted as a string) and backgroundColor
(the
background color of the field). Number fields, text fields, switch
fields and date and time fields support properties specific to them.
Similarly, list panel items, text boxes and groups support their
distinctive properties.
All panels are calculations. Panels feature properties such as
primaryColor
(the color
which, if not overridden, is used for the navigation bar background,
button labels and more), fieldValueColor
(the
color used for field values) and nextPanelAvailable
(whether the user should be allowed to navigate forward to the next
panel).
There is a top-level calculation which features properties such as
zoomLevel
(a value determining the visual size of the app), userEmailAddress
(the
email address of the user signed into a private app) and operatingSystem
(the
operating system used on the device running the app). This
calculation is normally named App
, if not overridden
by the app author.
All properties are documented in Calcapp Creator’s reference sidebar.
Unlike this documentation, though, property names provided to this
function must use a lower-case letter for the first letter of the
property name. (Use visible
and not
Visible
.)
Calcapp types in JavaScript
Calcapp numbers are mapped to JavaScript numbers, Calcapp logical
values are mapped to boolean
values and
Calcapp text strings are mapped to JavaScript strings. Blank values
in Calcapp are mapped to null
values in
JavaScript. Runtime errors (such as division by zero errors) are
mapped to objects whose error
property is
true
.
The returned promise
This function returns a Promise
object, which
represents a future value. Apps written with Calcapp run as part of
iframe
elements and the only way for a page embedding such apps to
communicate with them is through message passing. As such, values
cannot be returned directly (synchronously) and are only available at
some unspecified point in the future. The returned promise is said to
be resolved when the value becomes available, at which point
client-provided code can run. This code is given as a function to the
then()
function of the promise object:
calcappIframe.getValue("SomePanel", "SomeField").then(function(value) {
console.log("Value: " + value);
});
Errors should be handled by providing a function to the catch()
function of a
promise object:
calcappIframe.getValue("SomePanel", "SomeField").then(function(value) {
console.log("Value: " + value);
}).catch(function(error) {
console.error("Error: " + error);
});
Samples
To get the value of the field Field1
belonging to the
calculation panel MainPanel
, use the
following code (provided that there is only one iframe
element in the
document hosting an app written with Calcapp):
calcappIframe.getValue("MainPanel", "Field1").then(function(value) {
console.log("Value: " + value);
}).catch(function(error) {
console.error("Error: " + error);
});
To determine whether the field Field1
, belonging to
the calculation panel CalculationPanel1
, is
visible, use the following code:
calcappIframe.getValue("MainPanel",
"Field1",
"visible").then(function(value) {
console.log("Value: " + value);
}).catch(function(error) {
console.error("Error: " + error);
});
If there are multiple apps embedded in a single page, the app must be
identified. Clients can pass either the iframe
element hosting
the app directly as the fourth parameter, the alias of the app (such
as (abc123
)
or the numeric position of the iframe
element hosting
the app (in depth-first traversal order). Here, an app alias is
given:
calcappIframe.getValue("MainPanel",
"Field1",
"visible",
"abc123").then(function(value) {
console.log("Value: " + value);
}).catch(function(error) {
console.error("Error: " + error);
});
To read the email address of the user signed into a private app, use this code (provided that the top-level calculation has not been renamed):
calcappIframe.getValue("App",
null,
"userEmailAddress").then(function(value) {
console.log("Value: " + value);
}).catch(function(error) {
console.error("Error: " + error);
});
Parameters
calcappIframe.getValue(calculationName,
variableName,
propertyName,
app)
calculationName
string |
The name of the calculation which the identified variable or property belongs to. Panels are calculations. |
variableName
string (optional) |
The name of the variable which the identified property belongs to. Fields, text boxes, buttons, groups and list panel items are all variables. If this parameter is left undefined, the identified property is expected to reference a calculation property as opposed to a variable property. |
propertyName
string (optional) |
The name of the property whose value should be retrieved. If this parameter is left undefined, the value of the default property is returned instead. For fields, the default property is the value of the field. The first character of a property name must be lower-case. |
app
HTMLIFrameElement or string or number (optional) |
The app the value should be retrieved from. If this parameter
represents an iframe element,
the value is retrieved from the app hosted by said element. If
this parameter represents the number n, the value is
retrieved from the app hosted by the n-th iframe element in
the document hosting an app written with Calcapp, in
depth-first traversal order. If this parameter represents a
string, this string is expected to be an alias of an app
written with Calcapp, and the value is retrieved from the app
hosted by an iframe element in
the document referencing the app with the given alias. If this
parameter is undefined and there is only a single iframe element in
the document hosting an app written with Calcapp, the value is
retrieved from this app. If this parameter is undefined and
there are multiple iframe elements
hosting apps written with Calcapp, an exception is thrown.
|
Returns
Promise |
A promise which is resolved with the sought value or is rejected with an error message if there is a problem. |
Throws
Error |
|
calcappIframe.getValues
Returns a promise which is resolved with one value or multiple values
from an app built with Calcapp and hosted by an iframe
element, or is
rejected with an error message if there is a problem. To print the
value of field named Field1
, which is part
of a panel named MainPanel
, as well as
whether it is visible, use this code:
calcappIframe.getValues([{
calculationName: "MainPanel",
variableName: "Field1"
}, {
calculationName: "MainPanel",
variableName: "Field1",
propertyName: "visible"
}]).then(function(values) {
console.log("Field value: " + values[0]);
console.log("Is the field visible?: " + values[1]);
}).catch(function(error) {
console.error("Error: " + error);
});
This library communicates through message passing with the app hosted
by an iframe
element. As
such, retrieving multiple values through this function is far more
efficient than repeatedly invoking the getValue function.
For information on the Calcapp concepts discussed here, refer to the getValue documentation.
Parameters
calcappIframe.getValues(soughtValues, app)
soughtValues
Array |
An array of objects which hold information on a sought value.
This object must contain a property named calculationName
and can optionally contain properties named variableName and
propertyName .
These properties are identical to the calculationName ,
variableName and
propertyName
parameters given to the getValue
function; refer to its documentation for more information. The
resolved value of the returned promise corresponds to the array
given here; refer to the documentation for the return value for
more information.
|
app
HTMLIFrameElement or string or number (optional) |
The app the values should be retrieved from. If this parameter
represents an iframe element,
the values are retrieved from the app hosted by said element.
If this parameter represents the number n, the values
are retrieved from the app hosted by the n-th
iframe element in
the document hosting an app written with Calcapp, in
depth-first traversal order. If this parameter represents a
string, this string is expected to be an alias of an app
written with Calcapp, and the values are retrieved from the app
hosted by an iframe element in
the document referencing the app with the given alias. If this
parameter is undefined and there is only a single iframe element in
the document hosting an app written with Calcapp, the values
are retrieved from this app. If this parameter is undefined and
there are multiple iframe elements
hosting apps written with Calcapp, an exception is thrown.
|
Returns
Promise |
A promise which is resolved with an array of the sought values
or is rejected with an error message if there is a problem. The
element at index n of the resolved array corresponds
to the element at index n of the array given as the
soughtValues
parameter.
|
Throws
Error |
|
calcappIframe.subscribeToNewHeight
Starts subscribing to new height events from an app built
with Calcapp and hosted by an iframe
element and
returns a function which, when invoked, ends the subscription. A new
height event is communicated when an app starts and when a user takes
an action such that the height of the app changes. Such actions
include navigating to a new panel and entering a value in a field
such that a different field is made visible.
To have this library automatically adjust the height of an
iframe
element hosting an app written with Calcapp, use the function
manageHeight instead.
Sample
This sample subscribes to new height events and prints the new height to the console:
calcappIframe.subscribeToNewHeight(function(newHeight, iframe) {
console.log("New height: " + newHeight);
});
Parameters
calcappIframe.subscribeToNewHeight(listener, app)
listener
Function |
A function which is invoked with the new height, in pixels,
passed as its first parameter. The iframe element
hosting the app written with Calcapp is passed as the second
parameter.
|
app
HTMLIFrameElement or string or number (optional) |
The app whose events should be subscribed to. If this parameter
represents an iframe element,
the app hosted by this element is used as the subscription
target. If this parameter represents the number n, the
app hosted by the n-th iframe element in
the document hosting an app written with Calcapp, in
depth-first traversal order, is used as the subscription
target. If this parameter represents a string, this string is
expected to be an alias of an app written with Calcapp, and the
app hosted by an iframe element in
the document referencing the app with the given alias is used
as the subscription target. If this parameter is undefined and
there is only a single iframe element in
the document hosting an app written with Calcapp, this app is
used as the subscription target. If this parameter is undefined
and there are multiple iframe elements
hosting apps written with Calcapp, an exception is thrown.
|
Returns
Function |
A function which, when invoked, ends the subscription. |
Throws
Error |
|
calcappIframe.manageHeight
Starts automatically adjusting the height of the iframe
element hosting
the given app in response to the app changing its height and returns
a function which, when invoked, stops the process. The app typically
changes its height in response to the user navigating to a new panel
or entering a value in a field such that a different field is made
visible.
This function uses a mutation observer to automatically stop watching
the height of an app when the iframe
element hosting
it is removed.
Options
The second parameter is expected to be an object, with properties customizing the behavior of this function.
To ensure that the height of an iframe
element is not
set smaller than a certain value, set the minimumHeight
property
to the desired minimum height, in pixels. Similarly, to ensure that
the height of an iframe
element is not
set larger than a certain value, set the maximumHeight
attribute
to the desired maximum height, also in pixels.
Embedded apps and host pages communicate asynchronously. When the
height of an app changes using an animation, this library animates
the iframe
element to match the app height. When the app becomes larger, for
instance, the iframe
element may, at
times, lag behind the embedded app and momentarily not be large
enough to fully contain said app. As a result, a scrollbar may
appear, only for it to disappear a split second later when the
iframe
element is properly sized.
To prevent this situation from occurring, iframe
elements should
not be sized such that they precisely fit the embedded app. Rather,
they should be a number of pixels taller than the app. To achieve
this, set the extraHeight
property to
the number of pixels which should be added to the height of the app.
The default value is 16 pixels, which is appropriate for most apps.
For a perfectly snug fit, set this value to zero.
Declarative usage
This function can also be used declaratively, by adding the attribute
calcapp-managed-height
to the iframe
element. The
values passed through the options
parameter can
also be set this way. Use the calcapp-managed-height-minimum
attribute for the minimumHeight
option,
calcapp-managed-height-maximum
for the maximumHeight
option
and calcapp-managed-height-extra
for the extraHeight
option. The
data-
prefix may be used for all attributes.
When used declaratively, this function is called by this library in
response the DOMContentLoaded
event
firing on the window
object. As such,
using this method declaratively is only possible for iframe
elements present
when the page is initially loaded.
Sample
This sample asks the library to manage the height of an app written with Calcapp:
calcappIframe.manageHeight("abc123", {
minimumHeight: 200,
maximumHeight: 400,
extraHeight: 50
});
Parameters
calcappIframe.manageHeight(app, options)
app
HTMLIFrameElement or string or number (optional) |
The app whose events should be subscribed to. If this parameter
represents an iframe element,
the app hosted by this element is used as the subscription
target. If this parameter represents the number n, the
app hosted by the n-th iframe element in
the document hosting an app written with Calcapp, in
depth-first traversal order, is used as the subscription
target. If this parameter represents a string, this string is
expected to be an alias of an app written with Calcapp, and the
app hosted by an iframe element in
the document referencing the app with the given alias is used
as the subscription target. If this parameter is undefined and
there is only a single iframe element in
the document hosting an app written with Calcapp, this app is
used as the subscription target. If this parameter is undefined
and there are multiple iframe elements
hosting apps written with Calcapp, an exception is thrown.
|
options
Object |
An object containing various options for this function, as described above. |
Returns
Function |
A function which, when invoked, stops watching the height. |
Throws
Error |
|