Scope
Any variable recorded in scope is available in a template.
class MyComponent extends Akili.Component {
constructor(el, scope) {
super(el, scope);
scope.example = 'Example!';
console.log(this.scope === scope); // true
}
}
<my-component>${ this.example }</my-component>
Inside the element above, we'll get Example! instead of the expression, after the compilation. As you can see scope in the component is the same object as this in the template.
The scope content
In the scope you can store any type of javascript variables, except objects with circular references. You can also save functions and call them at any time.
class MyComponent extends Akili.Component {
constructor(...args) {
super(...args);
this.scope.test = (str) => {
return str + ' example';
}
}
}
<my-component>${ this.test('my') }</my-component>
Scopes hierarchy
The componen structure has a hierarchical structure. Each scope is inherited from the parent scope through the prototype mechanism.
class ParentComponent extends Akili.Component {
constructor(...args) {
super(...args);
this.scope.example = 'Example';
this.scope.unique = 'unique!';
}
}
class ChildComponent extends Akili.Component {
constructor(...args) {
super(...args);
this.scope.example = 'ExampleTwo';
}
}
<parent-component>
<child-component>
${ this.example } is ${ this.unique }
</child-component>
</parent-component>
Inside the element above, we'll see ExampleTwo is unique! But you also can get access to the parent component scope.
<parent-component>
<child-component>
${ this.__parent.example } is ${ this.unique }
</child-component>
</parent-component>
There will be Example is unique!
Proxy
Scope of the component is a javascript Proxy object.
You can't use the same object in different scope variables. Every proxy object will create a copy of the target object and all nested objects.
class MyComponent extends Akili.Component {
created() {
let obj = {};
this.scope.x = obj;
this.scope.y = this.scope.x;
console.log(this.scope.x === obj); // false;
console.log(this.scope.y === obj); // false;
console.log(this.scope.x === this.scope.y); // false;
}
}
All plain objects inside the scope are proxy too.
class MyComponent extends Akili.Component {
created() {
this.scope.example = ['ex', 'am', 'pl', 'e'];
}
compiled() {
this.scope.example[0] = 's';
}
}
<my-component>${ this.example.join('') }</my-component>
The expression result will be sample;
Parsing
By default, we use javascript new Function() for parsing. You can upgrade the parser rewriting Component.parse method. To parse some piece of code in html, you need to write an expression in the following form:
${ your javascript expression }
Such expressions might be anywhere in your templates including element attributes.
Globals
If you want to get a global variable inside the expression it is better to use Akili.globals.
import globals from 'akili/src/globals';
console.log(globals === Akili.globals); // true
globals.my = "global variable";
<div data="${ my }"></div>
Custom scope
If you need your own scope in the component you take scope property.
import Scope from 'akili/src/scope';
class MyScope extends Scope {
init() {
this.example = 'Hello';
}
}
class MyComponent extends Akili.Component {
static scope = MyScope;
created() {
this.scope.init();
}
}
<my-component>${ this.example }</my-component>
To use some auxiliary variable in your scope functions you need to start it with two characters _ or property might be just an underscore. Otherwise, this variable will be monitored like any other in the scope.