DocsCookbookCommunityGitHub →

List rendering

Using repeat attribute

To create the dynamic list inside your component, use repeat HTML attribute for the list container element in your template:

MyComponent.template = /*html*/ `
<div repeat="userList">
  <div>{{firstName}}</div>
  <div>{{secondName}}</div>
</div>`;

The attribute value should point to the certain key in component's data context:

class MyComponent extends BaseComponent {

  init$ = {
    userList: [
      {
        firstName: 'John',
        secondName: 'Snow',
      },
      {
        firstName: 'Peter',
        secondName: 'Sand',
      },
    ],
  };

}

Of course, you can use any type of data context. For example, inherited:

MyComponent.template = /*html*/ `
<div repeat="*userList">
  ...item template
</div>`

Or named:

MyComponent.template = /*html*/ `
<div repeat="APP/userList">
  ...item template
</div>`;

More details about data context types, you can find in the "Data context" section.

List items

All list items in the resulting list - are Symbiote components. That means they have all described APIs accessible and you can interact with them same way. All items are wrapped with a corresponding custom element. So, if you don't need to have an extra container for your styling purposes, use display: contents CSS property for such containers. This property will be added to each item by default, if you don't set the custom tag names for your list items.

To create custom named tag for your list items, use repeat-item-tag attribute:

MyComponent.template = /*html*/ `
<div repeat="userList" repeat-item-tag="user-card">
  <div>{{firstName}}</div>
  <div>{{secondName}}</div>
</div>`;

In this case, you can use that tag as the CSS selector:

user-card {
  display: flex;
}

If you planning to add some additional functionality for the each list item, you can pre-define your list item component:

class UserCard extends BaseComponent {

  init$ = {
    firstName: '',
    secondName: '',
  };

  initCallback() {
    this.onclick = () => {
      alert(`Hello ${this.$.firstName} ${this.$.secondName}!`);
    };
  }
}

UserCard.reg('user-card');

Now, this component will be used as the list item.

List item template

Each item will be created with a template, taken from container initial inner contents. Meant this part:

<div>{{firstName}}</div>
<div>{{secondName}}</div>

Note, that data binding keys will be connected with a fields of each data entry, not the parent component itself.

Data types and structure

The source data for the lists could be an Array or Object collections. Each item descriptor should have a flat structure, the same as the standard Symbiote Data storage. Nested properties are not supported by design.

In case of Object data collection, all item keys will be reflected for the each item with the _KEY_ property:

class MyComponent extends BaseComponent {

  init$ = {
    userList: {
      id1: {
        firstName: 'John',
        secondName: 'Snow',
      },
      id2: {
        firstName: 'Peter',
        secondName: 'Sand',
      },
    },
  };

}

MyComponent.template = /*html*/ `
<div repeat="userList" repeat-item-tag="user-card">
  <div>{{_KEY_}}</div>
  <div>{{firstName}}</div>
  <div>{{secondName}}</div>
</div>`;

Dynamic updates

To update your list, set the new data collection in the Symbiote data context:

class MyComponent extends BaseComponent {

  init$ = {
    userList: null,
  };

  async initCallback() {
    this.$.userList = await (await window.fetch('https://<MY-DATA-ENDPOINT>.io')).json();
  }

}

If data collection size is constant, you can use the complete data for the initial item rendering, and then to provide changes only:

class MyComponent extends BaseComponent {

  init$ = {
    userList: [
      // Initial full data:
      {
        firstName: 'John',
        secondName: 'Snow',
      },
      {
        firstName: 'Peter',
        secondName: 'Sand',
      },

    ],
  };

  initCallback() {
    this.$.userList = [
      // Updates only:
      {
        secondName: '<SOME FIXED DATA>',
      },
      {
        secondName: '<SOME FIXED DATA>',
      },
    ];
  }

}

The null or false in list data value will clear the entire list.

Live example

https://symbiotejs.github.io/examples/dynamic-list/dynamic-list_ref.html (source code)