Default components

It is implemented a lot of components for the system elements. They are in the Akili.components.

Loops

class MyComponent extends Akili.Component {
  constructor(...args) {
    super(...args);

    this.scope.data = [];

    for (let i = 1; i <= 10; i++) {
      this.scope.data.push({ title: 'value' + i });
    }
  }
}
<my-component>
  <for in="${ this.data }">
    <loop>${ this.loopIndex } <br> ${ this.loopKey} <br> ${ this.loopValue.title }</loop>
  </for>
</my-component>

for component data might be an object or an array. In the example above, component loop will be created 10 times with its own scope for each instance. Every instance has loopValue which is the value of the current data item.

  • scope.loopIndex - index of the current item
  • scope.loopKey - key of the current item.
  • scope.loopValue - value of the current item

Component for is already integrated into many system elements that require the similar logic.

<my-component>
  <ul in="${ this.data }">
    <li>${ this.loopValue }</li>
  </ul>
</my-component>
<my-component>
  <ol in="${ this.data }">
    <li>${ this.loopValue }</li>
  </ol>
</my-component>
<my-component>
  <table>
    <thead in="${ this.data }">
      <tr in="${ [1, 2, 3] }" class="${ this.__parent.loopValue.title }">
        <th>${ this.loopValue }</th>
      </tr>
    </thead>
    <tbody in="${ this.data }">
      <tr in="${ [1, 2, 3] }">
        <td>${ this.loopValue }</td>
      </tr>
    </tbody>
    <tfoot in="${ this.data }">
      <tr in="${ [1, 2, 3] }">
        <td>${ this.loopValue }</td>
      </tr>
    </tfoot>
  </table>
</my-component>

In the last example you can see that some elements might simultaneously be for and loop components. For example, it is tr component. Component loop provides this feature.

<my-component>
  <for in="${ this.data }">      
    <loop in="${ [1, 2, 3] }">
      <div component="loop" in="${ [1, 2, 3, 4, 5, 6] }">
        <loop>
          ${ this.loopValue } <br> ${ this.__parent.loopValue } <br> ${ this.__parent.__parent.loopValue }
        </loop>
      </div>
    </loop>
  </for>
</my-component>

If you don't specify the loop component inside the for it will happen automatically.

<my-component>
  <div component="for" in="${ this.data }">
    <div>${ this.loopValue }</div>
  </div>
</my-component>

However, in an unobvious situation you have to specify which element is an iterator.

<my-component>
  <ul in="${ this.data }">
    <li>Manual value at the start</li>
    <li component="loop">${ this.loopValue }</li>
    <li>Manual value at the end</li>
  </ul>
</my-component>

Conditional statements

class MyComponent extends Akili.Component {
  constructor(...args) {
    super(...args);

    this.scope.value = 0;
  }
}
<my-component>
  <if is="${ this.value === 0 }">0</if>
  <else-if is="${ this.value === 1 }">1</else-if>
  <else>2</else>
</my-component>

The components of conditional statements must be next to each other in obvious order. By default, everything inside the conditions is just hidden (display: none). If you need to remove hidden items from the DOM use boolean attribute recreate on the if component.

<my-component>
  <if recreate is="${ this.value === 0 }">0</if>
  <else>2</else>
</my-component>

Also you can use hidden attribute to hide some element.

<my-component>
  <div hidden="${ this.value !== 0 }">0</div>
</my-component>
Akili.services.router.add('app', '/app/:page', {
  templateUrl: '/templates/app.html'
});

class MyComponent extends Akili.Component {
  created() {
    this.scope.link = 'http://akilijs.com';
  }
}

The first way to go to the necessary route is click to a component with the attribute state. You can add attributes that is corresponded to the parameters of router.state function.

<my-component>
  <a state="app" params="${ {page: 'home'} }" query="${ {p: 1} }" hash="start">go to app</a>
  <route></route>
</my-component>

The second way is using the url attribute. In this case, it is like the router.location function.

<my-component>
  <a url="/app/home?p=1#start" options="${ {reload: true} }">go to the app</a>
  <route></route>
</my-component>

And if you just want to follow the link without using routing use the system attribute href.

<my-component>
  <a href="${ this.link }">go</a>
  <route></route>
</my-component>

To check the link status thera are two properties:

  • isActiveState - true if the current state is the same as the link state.
  • inActiveState - true if the link state is the part of the current state.

<a state="app" class="${ utils.class({active: this.isActiveState}) }">go to app</a>

Html templates

<include
  url="/templates/app.html"
  on-load="${ // loaded }"
  on-error="${ // error }"
  cache="500"
></include>

The url template will be inside the include element after the loading. We also enable the cache here.

Select

class MyComponent extends Akili.Component {
  constructor(...args) {
    super(...args);

    this.scope.data = [];

    for (let i = 1; i <= 10; i++) {
      this.scope.data.push({ title: 'value' + i });
    }
  }
}
<my-component>
  <select in="${ this.data }">
    <option value="${ this.loopValue.title }">${ this.loopValue.title }</option>
  </select>
</my-component>

If the option value is the same as its content you can skip the attribute value.

<my-component>
  <select in="${ this.data }">
    <option>${ this.loopValue.title }</option>
  </select>
</my-component>

To change the selected option in any time use the attribute value for the select.

<my-component>
  <select in="${ this.data }" value="${ this.selectValue }">
    <option>${ this.loopValue.title }</option>
  </select>
</my-component>

If we change scope selectValue the selected option will be the corresponding. To get the changes use on-change event.

<my-component>
  <select
    in="${ this.data }"
    value="${ this.selectValue }"
    on-change="${ this.selectValue = event.target.content }"
  >
    <option>${ this.loopValue.title }</option>
  </select>
</my-component>

This is a kind of replacement for double binding.

Note that we used event.target.content instead of event.target.value. The matter is that the select might be a multiple. To be able to work with several selected options we added a new property content to the element that can be an array.

<my-component>
  <select
    in="${ this.data }"
    on-change="${ console.log(event.target.content) // 'value1' }"
  >
    <option>${ this.loopValue.title }</option>
  </select>
</my-component>
<my-component>
  <select
    in="${ this.data }"
    on-change="${ console.log(event.target.value) // 'value1' }"
  >
    <option>${ this.loopValue.title }</option>
  </select>
</my-component>
<my-component>
  <select
    multiple
    in="${ this.data }"
    on-change="${ console.log(event.target.content) // ['value1'] }"
  >
    <option>${ this.loopValue.title }</option>
  </select>
</my-component>
<my-component>
  <select
    multiple
    in="${ this.data }"
    on-change="${ console.log(event.target.value) // 'value1' }"
  >
    <option>${ this.loopValue.title }</option>
  </select>
</my-component>

Attribute multiple is a boolean attribute.

<my-component>
  <select
    in="${ this.data }"
    on-change="${ console.log(event.target.content) // 'value3' }"
  >
    <option selected="${ this.loopKey == 2 }">${ this.loopValue.title }</option>
  </select>
</my-component>

You also can use the selected boolean attribute to make option selected in some cases:

  • After the component compilation
  • After the in change

Checkboxes and radio

<input
  type="checkbox"
  checked="${ this.isChecked }"
  on-change="${ this.isChecked = event.target.checked }"
  value="1"
/>
<input
  type="radio"
  checked="${ this.isChecked }"
  on-change="${ this.isChecked = event.target.checked }"
  value=