forio Toggle navigation

Flow.js: Overview

Flow.js provides two-way data bindings between variables and operations in your project's model and HTML elements in your project's user interface. In this way, Flow.js decouples the model from its interface. This is beneficial as a general design principle, and can be especially helpful for larger development teams where the UI developers and the modelers are different people. If you are comfortable writing HTML and basic JavaScript, using Flow.js can save you significant development time.

In particular, Flow.js provides a channel between the variables and operations in your model and the HTML elements in your interface. You simply reference model variables directly within HTML elements, and these values automatically update as the model changes; Flow.js takes care of all of the details.

Learn more about the basics:

Learn more about advanced topics:

The current version of Flow is 0.12.0. See the Using Flow.js in your Project section below. You can also view the history of releases on GitHub.

Using Flow.js in your Project

To use Flow.js in your project:

  1. Add the Flow.js required libraries to your project. Flow.js requires the following files:
    • jquery.js: document manipulation, DOM element selection, and event handling used by Flow.js
      • NOTE: Flow.js requires version 3.x of jquery.js.
    • lodash.js: utilities and performance enhancements used by Flow.js; also used in templating
      • NOTE: Flow.js requires version 2.x of lodash.js.
    • epicenter.js: Epicenter API Adapters with services and utilities for connecting to project models using the underlying Epicenter RESTful APIs.
  2. Add Flow.js itself to your project. The latest version of the Flow.js library is available from our set of tools: https://forio.com/tools/js-libs/flow/latest/flow.min.js. (You can also review previous versions and detailed release notes on GitHub.)
  3. Call the Flow.initialize() method. This tells Flow.js to create and initialize a run for you. (Runs are sets of particular user interactions with your project.)
  4. In order to finish initializing a run, Flow.js needs to know the name of the model. Add the attribute data-f-model to the <body> tag. Set the value to the name of your model file.

Example:

    <html>
        <head>
            <script src="//ajax.googleapis.com/ajax/libs/jquery/3.1.0/jquery.min.js"></script>
            <script src="//cdnjs.cloudflare.com/ajax/libs/lodash.js/2.4.1/lodash.js"></script>
            <script src="//forio.com/tools/js-libs/2.2.0/epicenter.min.js"></script>
            <script src="//forio.com/tools/js-libs/flow/latest/flow.js"></script>

            <script>
            $(function() { Flow.initialize(); });
            </script>
        </head>
        <body data-f-model="model.vmf">

        </body>
    </html>

Notes:

The Flow.initialize() call optionally takes two arguments: channel, which includes a run, and dom.

The run is an object that includes:

  • account: Optional, User ID or Team ID
  • project: Optional, Project ID
  • model: Optional, name of primary model file (repeated from data-f-model in your HTML <body> tag)
  • files: Optional, object with name : value pairs for files with additional data to pass into your model, e.g. "files": {"file1": "myFirstFile.xlsx", "file2": "mySecondFile.xlsx"}. Only applicable to Vensim models, and optional then. See a complete example in How To: Use External Data in Vensim.

These parameters are optional because the run information defaults correctly based on the location of your user interface file within your Epicenter project and the data-f-model element in your <body> tag. But you can add it if desired:

    Flow.initialize({
        channel: {
            strategy: 'new-if-initialized',
            run: {
                model: 'supply-chain-game.py',
                account: 'acme-simulations',
                project: 'supply-chain-game'
            }
        }
    });

In fact, you can add any of the Model Run API parameters to the run object here. See also more details on customizing the Flow.initialize() method.

Additionally, the Flow.initialize() call returns a promise, which is resolved when initialization is complete:

    Flow.initialize(...).then(function() {
        // code that depends on initialization goes here
    });

Working with Templates

Several common JavaScript libraries embed a simple template engine, including lodash.js, which Flow.js already requires as one of its dependencies. You can use this templating in your project's user interface.

Some basic examples are adding variables to an enclosing tag and working with array variables:

<div data-f-bind="CurrentYear, Revenue, Profit">
    In <%= CurrentYear %>, 
    our company earned <%= Revenue %>, 
    resulting in <%= Profit %>.
</div>

<ul data-f-foreach="Time">
    <li> Year <%= index %>: <%= value %> </li>
</ul>

But don't feel limited by these examples — you can use templates throughout your project's user interface code if you're using Flow.js.

Here are a few additional examples to get you started:

<!-- use templates to perform calculations easily -->

You have <strong data-f-bind="Time"><%= 2020 - value %></strong> years remaining in your simulation.


<!-- use templates to display dynamic content
        this is particularly useful for multiplayer games
        safe for Chrome, Firefox, Safari, and IE11+ -->

<div id="importantInfo"></div>

<script>
    if (condition) {
        $(#importantInfo).append("<h2 data-f-bind='Revenue'></h2>");
    } else {
        $(#importantInfo).append("<h2 data-f-bind='Sales'></h2>");
    }
</script>

Notes

  • Everything within your template (<%= %>) is evaluated as JavaScript. In particular, this means that model variables whose names include spaces (as is common in Vensim and SimLang) cannot be referenced. We anticipate being able to fix this from the Flow.js side in a future release.

  • Because everything within your template (<%= %>) is evaluated as JavaScript, you can use templates to pass expressions to other Flow.js attributes. For example,

      <div data-f-bind="myCurrentTimeStep">
          <div data-f-bind="Revenue[<%= value + 1%>]"></div>
      </div>
    

    will display the value of Revenue[myCurrentTimeStep + 1] (for example an estimate of future revenue in your model).

  • For more background on templates in lodash.js, see the lodash documentation. If you prefer to use underscore instead, that works too — just be sure to replace lodash.js with the underscore.js library in your page.