This article walks through embedding a xap in a web page, interaction between the web page and the xap, and embedding a xap in an iframe. If all you want to do is deploy a xap outside your Studio, without a need to situate it anywhere in particular, check out the previewing and publishing article




Embedding Process


To embed a xap in a web page you must first publish changes to stage.  


Importing Exaptive Library


To begin embedding your xap, you will need to import the Exaptive library via a script tag (preferably in the HEAD of your document), like so:

 

<head>
    ...
    <script src="https://exaptive.city/api/v1/js/exaptive-dataflow.bundle.min.js"></script>
</head>

 

If the page must support older browsers, like Internet Explorer, a Polyfill should be included above the main Exaptive bundle, like so:

<script src="https://exaptive.city/api/v1/city-assets/lib/bundles/polyfill.min.js"></script>


Initializing the Xap


Before initializing the xap it is required that you set the URL of the desired City with the setCitySettings call:


exaptive.setCitySettings({ url: 'https://exaptive.city/api/v1' })

  

Note that the /api/v1 is included and required for this step.


Now we can initialize the Xap using xap.create method.

 

try {
  var xap = exaptive.xap.create('{{xap-uuid}}', '{{HTML Element ID}}');
} catch(err) {
  console.error(err);
}


 

The HTML Element ID is where you will put the ID of the container you want your xap to be initialized in.


The xap UUID is its own unique identifier. The easiest way to find your xap's UUID is checking the URL of your xap's dashboard.

  

https://exaptive.city/#/studio/xaps/{{xap-uuid}}

 

 Creating the xap in a try/catch statement is recommended for debugging ease.



Xap Interaction


Adding Input/Output components


To begin we will start with a simple xap containing a single TextBox component.


We will then add an input and an output component to your xap to interact with the external web page your xap will be embedded in. Both are located under the TOOLS menu item.


You have the ability to change the channel, so to speak, of both the input and outputs via the "name"  port. Make note of what you change them to, otherwise by default they are just "input" and "output." 


Now we can wire up the components.


Add a connection from the input component's "data" output port to the TextBox component's "value" input port. (The "value"  port changes the text inside the textbox).


Let's also add a connection from the TextBox component's "change" output port to the output component's "data" input port. (The "change" port triggers on keystrokes inside the textbox.)


Using the Xap interaction API


Now that we have added the input/output components to our xap, we can use the interaction API to input/retrieve data to/from our xap.


Earlier upon initializing the xap we saved it to the variable name "xap," so we have access to the two following methods:

 

xap.input('channel', data);
xap.setOutputHandler('channel', function(data) {});


 

Note that you will want to set the channel to whatever you might have changed the channel to on the corresponding input/output components.


Here's a full example of two-way binding a textbox on our web page to inside our xap we created:

    

<body>
  <input id="myInput">
  <div id="myXap"></div>
    <script>
    try {
        exaptive.setCitySettings({ url: 'https://exaptive.city/api/v1' });
        var xap = exaptive.xap.create('my-xap-uuid', 'myXap');
        var input = document.getElementById('myInput');

        input.addEventListener('input', function() {
            xap.input('input', input.value);
        });

        xap.setOutputHandler('output', function(data) {
            input.value = data;
        });
    } catch(e) {
      console.log(e);
    }
    </script>
</body>

    

Embedding in an Iframe


Sometimes an embedded xap can interfere with the styling of the page where you've embedded it. There are two solutions to that issue: 


  1. Use very specific class names for components that have styling. 
  2. Embed your xap in an iframe, so its styling is encapsulated. 
Here's how to use an iframe. 


 

<!DOCTYPE html>
<html>
  <head>
    <meta charset="utf-8">
    <title>Xap Embed Test</title>
    <style media="screen">
      #xapIframe {
        border: none;
      }
    </style>
  </head>
  <body>
    <iframe id="xapIframe"></iframe>

    <script type="text/javascript">
      var xapUuid = 'ccb02da0-96f9-11e6-a13c-89914c3fe8a7';

      // Get the iframe element to inject the xap in
      var iframe = document.getElementById('xapIframe');
      var iframeWindow = iframe.contentWindow;
      var iframeDocument = iframe.contentDocument;
      iframeDocument.open();

      // Write a simple page into the iframe that loads the xap
      iframeDocument.write(
        '<html>' +
        '  <head>' +
        '    <script src="https://exaptive.city/api/v1/js/exaptive-dataflow.bundle.min.js"><\/script>' +
        '  </head>' +
        '  <body>' +
        '    <div id="xapDiv"></div>' +
        '    <script type="text/javascript">' +
        '      exaptive.setCitySettings({ url: "https://exaptive.city/api/v1" });' +
        '      try {' +
        '        var embeddedXap = exaptive.xap.create("' + xapUuid + '", "xapDiv");' +
        '      } catch(err) {' +
        '        console.error(err);' +
        '      }' +
        '    <\/script>' +
        '  <\/body>' +
        '<\/html>'
      );
      iframeDocument.close();

      // Once the new iframe has loaded, we can get the xap variable for input/ouput handling
      iframe.onload = function() {
        iframeWindow.embeddedXap.input('channel', {});
        iframeWindow.embeddedXap.setOutputHandler('channel', function(data) {});
      };
    </script>
  </body>
</html>