Create Your Web Component
A `web-component` in `fastn` can be created using `web-component` keyword.
Here's an example of how to integrate a web component created using the standard
Web Components API.
class HelloWorld extends HTMLElement {
constructor() {
super();
const shadow = this.attachShadow({ mode: 'open' });
const div = document.createElement('div');
div.classList.add('hello-world');
div.textContent = 'Hello World!';
div.style.color = 'orange';
div.style.borderWidth = '1px';
div.style.borderColor = 'yellow';
div.style.borderStyle = 'dashed';
div.style.padding = '10px';
shadow.appendChild(div);
}
}
customElements.define('hello-world', HelloWorld);
;; component call
-- hello-world:
;; Create a web component
-- web-component hello-world:
js: web-component.js
-- end: word-count
In above code we have created a web component `hello-world` in
`web-component.js`. Then, we've included the web component in `fastn` using
the `web-component` , and used it in the `fastn` component tree using the
hello-world element. used it in `index.ftd`.
Data Across JS and `fastn` Worlds
When working with web components, it is possible to share the data between the
JS and `fastn` worlds, which can be managed and updated efficiently, reflecting
the changes in both worlds.
`fastn` provides a function `component_data` which exposes data arguments,
passed from `fastn` world, and it's access methods. There are three access
methods provided by `fastn`, against an argument:
- `get`: To get the value of the variable in `fastn`. This method is present for
both mutable and immutable variables.
- `set`: To set the value of the variable in `fastn`. The value set using this
method will reflect it's changes in `fastn` world. This method is present for
mutable variables only.
- `on-change`: To listen for any change in variable value in `fastn` world. This
method is present for both mutable and immutable variables.
Let's look at these in more detail.
A Web Component With Argument
Lets create a web component that takes an argument.
-- web-component num-to-words:
caption integer num:
js: web-component.js
class NumToWords extends HTMLElement {
constructor() {
super();
// `window.ftd.component_data` exposes the data
// arguments passed from `ftd` world.
let data = window.ftd.component_data(this);
// `get()` method gives the value of the argument
// passed.
let num = data.num.get();
const shadow = this.attachShadow({ mode: 'open' });
const div = document.createElement('div');
div.textContent = numberToWords(num);
div.style.color = 'orange';
div.style.borderWidth = '1px';
div.style.borderColor = 'yellow';
div.style.borderStyle = 'dashed';
div.style.padding = '10px';
shadow.appendChild(div);
}
}
customElements.define('num-to-words', NumToWords);
function numberToWords(num) {
// some code here
}
Now lets call this component and pass a data.
We have seen how data can be passed from `fastn` and consumed by `js`.
Working with mutable data
Now let's mutate the data and correspondingly change the output from `js`
world.
-- integer $num: 0
-- ftd.integer: $num
-- ftd.text: I increment the `num`
$on-click$: $ftd.increment($a = $num)
-- num-to-words: $num
class NumToWords extends HTMLElement {
constructor() {
super();
let data = window.ftd.component_data(this);
let num = data.num.get();
const shadow = this.attachShadow({ mode: 'open' });
const div = document.createElement('div');
div.textContent = numberToWords(num);
div.style.color = 'orange';
div.style.borderWidth = '1px';
div.style.borderColor = 'yellow';
div.style.borderStyle = 'dashed';
div.style.padding = '10px';
// `on_change()` method listen to any changes done
// against the argument value in ftd.
data.num.on_change(function () {
const changed_value = data.num.get();
div.textContent = numberToWords(changed_value);
})
shadow.appendChild(div);
}
}
In above example, we have added a mutable variable `num`, whose value can be
changed by an event in `fastn`. This changes is then listen using `on-change`
function which do the necessary changes in `js` world.
Now let mutate the data from `js` world too.
class NumToWords extends HTMLElement {
constructor() {
super();
let data = window.ftd.component_data(this);
let num = data.num.get();
const shadow = this.attachShadow({ mode: 'open' });
const div = document.createElement('div');
div.textContent = numberToWords(num);
div.style.color = 'orange';
div.style.borderWidth = '1px';
div.style.borderColor = 'yellow';
div.style.borderStyle = 'dashed';
div.style.cursor = 'pointer';
div.style.padding = '10px';
div.onclick = function (_) {
let current_num = data.num.get();
current_num -= 1;
div.textContent = numberToWords(current_num);
data.num.set(current_num);
}
data.num.on_change(function () {
const changed_value = data.num.get();
div.textContent = numberToWords(changed_value);
});
shadow.appendChild(div);
}
}
-- num-to-words:
$num: $num
-- web-component num-to-words:
caption integer $num:
js: web-component.js
In the above code as you can see that we are passing the mutable reference of
`num` variable to the web-component `num-to-words` which then decrements by it.