Table of Contents |
---|
Purpose
To demonstrate how to create an elementary component using the Coder DevTools
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:
Code Block | ||||
---|---|---|---|---|
| ||||
> 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:
Code Block | ||||
---|---|---|---|---|
| ||||
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:
fixer-io-wrapper.html:
provides a template for the elementary component using Polymer codefixer-io-wrapper.js:
contains the logic for the elementary componentfixer-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".
Code Block | ||||
---|---|---|---|---|
| ||||
"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.
Code Block | ||||||||
---|---|---|---|---|---|---|---|---|
| ||||||||
"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
- Start the embedded webserver using the
+startWebserver
grunt task available in the DevTools. - 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:
Code Block | ||||||||
---|---|---|---|---|---|---|---|---|
| ||||||||
<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:
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 * Access the Cubbles-Component-Model: * > Access slot values: * slot 'a': this.getA(); | this.setA(value) */ CubxPolymer({ is: 'fixer-io-wrapper', modelBaseChanged: function(newValue) { /** * Observe the 'base' slot //to update the view of this.$.base.setAttribute('value', newValue);this component and then * send this.sendQuery(); the request to the fixer-io api }, * @param {string} newValue modelDateChanged: function(newValue) { - new value of the slot *// update the view modelBaseChanged: function(newValue) { // update the view this.$.datebase.setAttribute('value', newValue); this.sendQuery(); }, modelCurrenciesChanged: function(newValue) {/** * Observe the //'date' slot to update the view of this.$.currencies.setAttribute('value', newValue); component and then this.sendQuery(); * send the request to the fixer-io api }, * submit: function(event) { @param {string} newValue - new value of the slot ('yyyy-mm-dd' format) event.preventDefault(); */ this.model.base = this.$.base.value; modelDateChanged: function(newValue) { this.model.date = this.$.date.value; // update the view this.model.currencies = this.$.currenciesdate.setAttribute('value', newValue); this.sendQuery(); }, sendQuery: function() {/** * Observe the slot // Makes sure all slots are defined if(this.getBase() && this.getCurrencies()) { 'currencies' to update the view of this component * and then send the request to the fixer-io api. var baseUrl = '//api.fixer.io/'; * @param {string} newValue - new value of the slot (coma separated var queryUrl = baseUrl + this.getDate(* currencies) + '?base=' + */ this.getBase() + '&symbols=' + this.getCurrencies();modelCurrenciesChanged: function(newValue) { // update the view console.log(queryUrl); var self = this; this.$.currencies.setAttribute('value', newValue); var xhttp = new XMLHttpRequest this.sendQuery(); xhttp.onreadystatechange = function() { }, if (this.readyState == 4 && this.status == 200) {/** var data = JSON.parse(xhttp.responseText); console.log(data); * 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]); }); var props = Object.getOwnPropertyNames(data.rates); // console.log(props); var rates = ['Rate']; Update the Cubbles component model slots using the setters var xLabels = []; propsself.forEachsetCurrenciesLabels(function(p) {xLabels); xLabels.push(p); self.setRates([rates]); rates.push(data.rates[p]); } }); self.setCurrenciesLabels(xLabels);}; self.setRates([rates]); } }; xhttp.open("GET", queryUrl, true); xhttp.send(); } } }); }()); |
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.