Virtual List

Virtual List allows to render lists with huge amount of elements without loss of performance. And it is fully compatible with all Framework7 components which work with lists such as Search Bar, Infinite Scroll, Pull To Refresh, Swipeouts (swipe-to-delete) and Sortable.

Virtual List Layout

Virtual List HTML layout is pretty simple, it is almost the same as for usual List View with only difference: you need to leave it empty:

<!-- Virtual List -->
<div class="list virtual-list">
  <!-- keep it empty -->
</div>

Where:

Virtual List App Methods

Now, when we have list's HTML, we need to initialize it. We need to use required App method:

app.virtualList.create(parameters)- initialize virtual list with parameters

  • parameters - object - object with virtual list parameters. Required.
  • Method returns initialized Virtual List instance

app.virtualList.destroy(el)- destroy Virtual List instance

  • el - HTMLElement or string (with CSS Selector) or object. Virtual List element or Virtual List instance to destroy.

app.virtualList.get(el)- get Virtual List instance by HTML element

  • el - HTMLElement or string (with CSS Selector). Virtual List element.

Method returns Virtual List's instance

Note that Virtual List container (list block element) should be in DOM on a moment of initialization.

Virtual List Parameters

Let's look on list of all available parameters:

ParameterTypeDefaultDescription
elHTMLElement
string
Target List Block element. In case of string - CSS selector of list block element
ulHTMLElement
string
List element <ul> inside of List block.
createUlbooleantrueWill automatically create <ul> element inside of Virtual List block. If disabled, then virtual list can be used on any block element without ul > li structure
itemsarrayArray with list items
rowsBeforenumberAmount of rows (items) to be rendered before current screen scroll position. By default it is equal to double amount of rows (items) that fit to screen
rowsAfternumberAmount of rows (items) to be rendered after current screen scroll position. By default it is equal to the amount of rows (items) that fit to screen
colsnumber1Number of items per row. Doesn't compatible when using Virtual List with dynamic height
heightnumber or function(item) or "auto"

If number - list item height in px.

If function then function should return item height. By default equals to 44 for iOS theme, 48 for MD theme

If "auto" it will calculate each item height automatically. It can work a bit slower in this case, but still much better when it is impossible to determine or predict item height

renderItemfunction(item)This optional function allows to use custom function to render item HTML. It could be used instead of template parameter
renderExternalfunction(vl, renderParameters)This optional function allows to render DOM items using some custom method. Useful in case it is used (e.g.) with Vue/React plugin to pass DOM rendering and manipulation to Vue/React. renderParameters conaints object with the following properties: fromIndex, toIndex, listHeight, topPosition, items
emptyTemplatestringDefines list item template for the case if empty data passed
dynamicHeightBufferSizenumber1This parameter allows to control buffer size on Virtual Lists with dynamic height (when height parameter is function) as a buffer size multiplier
cachebooleantrueDisable or enable DOM cache for already rendered list items. In this case each item will be rendered only once and all further manipulations will be with DOM element. It is useful if your list items have some user interaction elements (like form elements or swipe outs) or could be modified
updatableScrollbooleanIs the current device updates and handles scroll events during scroll. By default (if not specified) it is "false" for all iOS devices with iOS version less than 8.
setListHeightbooleantrueWill set height on list block if enabled
showFilteredItemsOnlybooleanfalseOption to show filtered items only set by method
scrollableParentElHTMLElement
string
Virtual list's scrollable parent. If not specified, then it will look for parent <div class="page-content"> element
Searchbar
searchByItemfunction(query, item, index)Search function that will be used by Searchbar, it receives search query, item itself and item index. If item matches to search query you need to return true, otherwise this function should return false
searchAllfunction(query, items)Search function that will be used by Searchbar, it receives search query and array with all items. You need to loop through items and return array with indexes of matched items

Virtual List Methods & Properties

So to create Virtual List we have to call:

var virtualList = app.virtualList.create({ /* parameters */ })

After we initialize Virtual List we have its initialized instance in variable (like virtualList variable in example above) with helpful methods and properties:

Properties
virtualList.itemsArray with items
virtualList.filteredItemsArray with filtered items (after using ".filterItems" method)
virtualList.domCacheObject with cached dom items
virtualList.paramsParameters passed on list initialization
virtualList.elVirtual list target list block element
virtualList.$elDom7 instance of target list block element
virtualList.pageContentElParent "page-content" element
virtualList.$pageContentElDom7 instance of parent "page-content" element
virtualList.currentFromIndexIndex number of currently first rendered item
virtualList.currentToIndexIndex number of currently last rendered item
virtualList.reachEndBoolean property. Equals true if the currently last rendered item is the last item of all specified items
Methods
virtualList.filterItems(indexes);Filter virtual list by passing array with indexes of items to show
virtualList.resetFilter();Disable filter and display all items again
virtualList.appendItem(item);Append item to virtual list
virtualList.appendItems(items);Append array with items to virtual list
virtualList.prependItem(item);Prepend item to virtual list
virtualList.prependItems(items);Prepend array with items to virtual list
virtualList.replaceItem(index, item);Replace item at specified index with the new one
virtualList.replaceAllItems(items);Replace all items with arrays of new items
virtualList.moveItem(oldIndex, newIndex);Move virtual item from oldIndex to newIndex
virtualList.insertItemBefore(index, item);Insert new item before item with specified index
virtualList.deleteItem(index);Delete item at specified index
virtualList.deleteItems(indexes);Delete items at specified array of indexes
virtualList.deleteAllItems();Delete all items
virtualList.clearCache();Clear virtual list cached DOM elements
virtualList.destroy();Destory initialized virtual list and detach all events
virtualList.update();Update virtual list, including recalculation of list sizes and re-rendering of virtual list
virtualList.scrollToItem(index);Scroll Virtual List to specified item by its index number

Virtual List Events

Virtual List will fire the following events on app and virtual list instance:

Virtual List instance emits events on both self instance and app instance. App instance events has same names prefixed with vl.

EventTargetArgumentsDescription
itemBeforeInsertvirtualListvirtualList, itemEl, itemEvent will be triggered before item will be added to virtual document fragment
vlItemBeforeInsertapp
itemsBeforeInsertvirtualListvirtualList, fragmentEvent will be triggered after current DOM list will be removed and before new document will be inserted
vlItemsBeforeInsertapp
beforeClearvirtualListvirtualList, fragmentEvent will be triggered before current DOM list will be removed and replaced with new document fragment
vlBeforeClearapp
itemsAfterInsertvirtualListvirtualList, fragmentEvent will be triggered after new document fragment with items inserted
vlItemsAfterInsertapp

Examples

virtual-list.html
<template>
  <div class="page">
    <div class="navbar">
      <div class="navbar-bg"></div>
      <div class="navbar-inner sliding">
        <div class="title">Virtual List</div>
        <div class="subnavbar">
          <form data-search-container=".virtual-list" data-search-item="li" data-search-in=".item-title"
            class="searchbar searchbar-init">
            <div class="searchbar-inner">
              <div class="searchbar-input-wrap">
                <input type="search" placeholder="Search" />
                <i class="searchbar-icon"></i>
                <span class="input-clear-button"></span>
              </div>
              <span class="searchbar-disable-button">Cancel</span>
            </div>
          </form>
        </div>
      </div>
    </div>
    <div class="searchbar-backdrop"></div>
    <div class="page-content">
      <div class="block">
        <p>Virtual List allows to render lists with huge amount of elements without loss of performance. And it is fully
          compatible with all Framework7 list components such as Search Bar, Infinite Scroll, Pull To Refresh, Swipeouts
          (swipe-to-delete) and Sortable.</p>
        <p>Here is the example of virtual list with 10 000 items:</p>
      </div>
      <div class="list list-strong list-outline-ios inset-md list-dividers-ios links-list">
        <ul>
          <li>
            <a href="/virtual-list-vdom/">Virtual List VDOM</a>
          </li>
        </ul>
      </div>
      <div class="list list-strong list-outline-ios inset-md list-dividers-ios simple-list searchbar-not-found">
        <ul>
          <li>Nothing found</li>
        </ul>
      </div>
      <div class="list list-strong list-outline-ios inset-md list-dividers-ios virtual-list media-list searchbar-found">
      </div>
    </div>
  </div>
</template>
<script>
  export default (props, { $f7, $el, $theme, $onMounted, $onBeforeUnmount }) => {
    let items = [];
    let virtualList;
    for (let i = 1; i <= 10000; i++) {
      items.push({
        title: 'Item ' + i,
        subtitle: 'Subtitle ' + i
      });
    }
    $onMounted(() => {
      virtualList = $f7.virtualList.create({
        // List Element
        el: $el.value.find('.virtual-list'),
        // Pass array with items
        items,
        // Custom search function for searchbar
        searchAll: function (query, items) {
          var found = [];
          for (var i = 0; i < items.length; i++) {
            if (items[i].title.toLowerCase().indexOf(query.toLowerCase()) >= 0 || query.trim() === '') found.push(i);
          }
          return found; //return array with mathced indexes
        },
        // List item render
        renderItem(item) {
          return `
          <li>
            <a  class="item-link item-content">
              <div class="item-inner">
                <div class="item-title-row">
                  <div class="item-title">${item.title}</div>
                </div>
                <div class="item-subtitle">${item.subtitle}</div>
              </div>
            </a>
          </li>`;
        },
        // Item height
        height: $theme.ios ? 65 : 69,
      });
    });

    $onBeforeUnmount(() => {
      virtualList.destroy()
    });

    return $render;
  }
</script>