Create an Elementary Component


Purpose

To demonstrate how to create an elementary component using the Coder DevTools

Prerequisites

The fixer-io-wrapper Elementary Component

We will create an elementary component called fixer-io-wrapper. Which is a component that uses the fixer.io webservice to get current and historical foreign exchange rates published by the European Central Bank. This component will have the following interface (input slots on the left and output slot on the right):

Create an Elementary Component

To create the elementary you should use the +webpackage-createElementary task from the DevTools:

> grunt +webpackage-createElementary

Then, provide the name for the component, in this case fixer-io-wrapper and a short description if you want (e.g.: Elementary component for the fixer-io webservice).

If everything is okay you will get:

Done, without errors.

Process finished with exit code 0

The grunt task will be executed and the file and folder structure for an elementary component will be created inside your webpackage folder as follows:

The newly created folder contains a demo and a docs folder and the following three files:

  1. fixer-io-wrapper.html: provides a template for the elementary component using Polymer code
  2. fixer-io-wrapper.js: contains the logic for the elementary component
  3. fixer-io-wrapper-style.html: contains CSS style definitions for the elementary component

In the background the manifest.webpackage file (located on the root level of your webpackage folder) has been modified. It includes some webpackage meta information and by the moment the elementary component with a slot definition of a slot "a".

"elementaryComponents": [
  {
    "artifactId": "fixer-io-wrapper",
    "description": "Elementary component for the fixer-io webservice",
    "runnables": [
      {
		...
]

Slot Definitions

We continue the development process by specifying slots according to the interface defined above. We need 4 slots for this elementary component, three input slots and one output slot. Slots are defined using JSON. So we can copy the definition of slot a and paste it three times and then change the slot definitions as follows.

        "slots": [
          {
            "slotId": "base",
            "type": "string",
            "direction": [
              "input"
            ],
            "value": "EUR"
          },
          {
            "slotId": "date",
            "type": "string",
            "direction": [
              "input"
            ],
            "value": "latest"
          },
          {
            "slotId": "currencies",
            "type": "string",
            "direction": [
              "input"
            ],
            "value": "USD,GBP,JPY"
          },
          {
            "slotId": "rates",
            "type": "array",
            "direction": [
              "output"
            ]
          },
		  {
  			"slotId": "currenciesLabels",
			"type": "array",
		   	"direction": [
    			"output"
		  	]
		  }
        ]

Now we have

  • Three input slots with initial values and
  • One output slot which provides the output data of this elementary.

Check Generated Documentation

Too check the generated documentation (i.e.interface view and details), perform the following steps

  1. Start the embedded webserver using the +startWebserver grunt task available in the DevTools. 
  2. Check the automatically generated docs: http://localhost:8282/<webpackage-name>/fixer-io-wrapper/docs/

It should look as follows:

Changing the View of the Elementary (.html File)

Now we need to change the template of the component which provides the visual part of the elementary component. For our we need an input interface for the input slots (where you choose the currencies, base, date).

Open the fixer-io-wrapper.html file and edit the template to be as shown bellow:

<link rel="import" href="fixer-io-wrapper-style.html">
<dom-module id="fixer-io-wrapper">
    <template>
        <style include="fixer-io-wrapper-style"></style>
    <div>
      <form action="" on-submit="submit">
        <label>Base:</label>
        <input type="text" id="base">
        <label>Date:</label>
        <input type="text" id="date">
        <label>Currencies:</label>
        <input type="text" id="currencies">
        <input type="submit" value="submit">
      </form>
    </div>
    <div id="result">
      <table>
    	<tbody>
    		<tr>
        		<td>
            		Currency <br>
            		<template is="dom-repeat" items="{{model.currenciesLabels}}">
                		{{item}} <br>
            		</template>
        		</td>
        		<td>
            		<template is="dom-repeat" items="{{model.rates.0}}">
                		{{item}} <br>
            		</template>
        		</td>
    		</tr>
    	</tbody>
	  </table>
    </div>
    </template>
    <script src="fixer-io-wrapper.js"></script>
</dom-module>


To see the result check the automatically generated demo page to reflect the changes: http://localhost:8282/<webpackage-name>/fixer-io-wrapper/demo/

Change the Logic of the Elementary (.js File)

The file fixer-io-wrapper.js handles what will happen when a slot value is changed. We should modify the implementation in order to handle the three different input values and send the https-request to the fixer.io Webservice and receive the response.

We basically delete everything provided in the template file that is related to slot a because we want to use slots the slots we defined in last section.

Instead we add some code to be called whenever an input-slot has been changed (a new value is set) - on a method for each input-slot.

Finally we create a method to send a query to the fixer.io webservice (in our case the name is "sendQuery").

For now we won't change the CSS style definitions which are set in the file fixer-io-wrapper-style.html.

Open the file fixer-io-wrapper.js and change it according to the following code block:

(function() {
    'use strict';
    /**
     * Get help:
     * > Lifecycle callbacks:
     * https://www.polymer-project.org/1.0/docs/devguide/registering-elements.html#lifecycle-callbacks
     *
     * Access the Cubbles-Component-Model:
     * > Access slot values:
     * slot 'a': this.getA(); | this.setA(value)
     */
    CubxPolymer({
        is: 'fixer-io-wrapper',

        /**
         * Observe the 'base' slot to update the view of this component and then
         * send the request to the fixer-io api
         * @param {string} newValue - new value of the slot
         */
        modelBaseChanged: function(newValue) {
            // update the view
            this.$.base.setAttribute('value', newValue);

            this.sendQuery();
        },
        /**
         * Observe the 'date' slot to update the view of this component and then
         * send the request to the fixer-io api
         * @param {string} newValue - new value of the slot ('yyyy-mm-dd' format)
         */
        modelDateChanged: function(newValue) {
            // update the view
            this.$.date.setAttribute('value', newValue);

            this.sendQuery();
        },
        /**
         * Observe the slot 'currencies' to update the view of this component
         * and then send the request to the fixer-io api.
         * @param {string} newValue - new value of the slot (coma separated
         * currencies)
         */
        modelCurrenciesChanged: function(newValue) {
            // update the view
            this.$.currencies.setAttribute('value', newValue);

            this.sendQuery();
        },
        /**
         * Submit the form, update the Component-Model and then send the request
         * to the fixer-io api.
         * @param event
         */
        submit: function(event) {
            event.preventDefault();
            // Update the Cubbles component model slots the setters
            this.setBase(this.$.base.value);
            this.setDate(this.$.date.value);
            this.setCurrencies(this.$.currencies.value);

            this.sendQuery();
        },
        /**
         * Send the request a to the fixer-io api.
         */
        sendQuery: function() {
            // Makes sure all slots are defined
            if(this.getBase() && this.getCurrencies()) {
                var baseUrl = '//api.fixer.io/';
                var queryUrl = baseUrl + this.getDate() + '?base=' +
                    this.getBase() + '&symbols=' + this.getCurrencies();

                var self = this;

                var xhttp = new XMLHttpRequest();
                xhttp.onreadystatechange = function() {
                    if (this.readyState == 4 && this.status == 200) {
                        var data = JSON.parse(xhttp.responseText);
                        console.log(data);
                        var props = Object.getOwnPropertyNames(data.rates);
                        console.log(props);
                        var rates = ['Rate'];
                        var xLabels = [];
                        props.forEach(function(p) {
                            xLabels.push(p);
                            rates.push(data.rates[p]);
                        });
                        // Update the Cubbles component model slots using the setters
                        self.setCurrenciesLabels(xLabels);
                        self.setRates([rates]);
                    }
                };
                xhttp.open("GET", queryUrl, true);
                xhttp.send();
            }
        }
    });
}());


It is useful to know that the component's slots values can be accessed using the method set<SlotName>(value) and edited using the get<SlotName>() method. Let's say manage the rates slot:

  1. To get its value we should use the getRates()
  2. To set a new value for the slot we use the setRates(newValue)

Both are use within the code above.

Now when the value of a slot changes or the submit button is clicked, a request will be sent.

To check whether it works, reload the demo on the browser (http://localhost:8282/<webpackage-name>/fixer-io-wrapper/demo/) and the result will be displayed below the form, as follows:

Try another date using the yyyy-mm-dd syntax, for example "2015-11-12". The values for the currencies should change after clicking the submit button.


For more details about the polymer syntax see Polymer Project.

For more details about Cubbles API see additional documentation in /wiki/spaces/RTE/pages/19435522.