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 HTML layout is pretty simple, it is almost the same as for usual List View or Media List View with only difference, you need to leave it empty:
<!-- Virtual List -->
<div class="list-block virtual-list">
<!-- keep it empty -->
</div>
Where:
virtual-list
- required additional class on any list-block that uses Virtual List
Now, when we have list's HTML, we need to initialize it. We need to use required App method:
myApp.virtualList(listBlockContainer, parameters) - initialize virtual list with parameters
For example:
var myList = app.virtualList('.list-block', {
items: [1,2,3,4],
height: 44
});
Let's look on list of all available parameters:
Parameter | Type | Default | Description |
---|---|---|---|
items | array | Array with list items | |
rowsBefore | number | Amount 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 | |
rowsAfter | number | Amount 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 | |
cols | number | 1 | Number of items per row. Doesn't compatible when using Virtual List with dynamic height |
height | number or function(item) | 44 | If number - item height in px. If function then function should return item height |
template | string or function | Template7 string template or Template7 compiled template that used to render single item. Template should contain full HTML layout for single item, including wrapping <li></li> tags |
|
renderItem | function(index, item) | This optional function allows to use custom function to render item HTML. It could be used instead of template parameter | |
renderExternal | function(vlInstance, 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 |
|
emptyTemplate | string | Defines list item template for the case if empty data passed | |
dynamicHeightBufferSize | number | 1 | This parameter allows to control buffer size on Virtual Lists with dynamic height (when height parameter is function) as a buffer size multiplier |
cache | boolean | true | Disable or enable DOM cache for already rendered list items. In this case each item will be rendered only once and all futher 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 |
updatableScroll | boolean | Is 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. | |
showFilteredItemsOnly | boolean | false | Option to show filtered items only set by `filter()` method |
Search | |||
searchByItem | function(query, index, item) | Search function that will be used by Search Bar, it receives search query, item index and item itself. If item matches to search query you need to return true , otherwise this function should return false |
|
searchAll | function(query, items) | Search function that will be used by Search Bar, it receives search query and array with all items. You need to loop through items and return array with indexes of matched items | |
Callbacks | |||
onItemBeforeInsert | function(list, item) | Callback function, will be executed before item will be added to virtual document fragment | |
onBeforeClear | function(list, fragment) | Callback function, will be executed before current DOM list will be removed and replaced with new document fragment | |
onItemsBeforeInsert | function(list, fragment) | Callback function, will be executed after current DOM list will be removed and before new document will be inserted | |
onItemsAfterInsert | function(list, fragment) | Callback function, will be executed after new document fragment with items inserted |
After we initialize Virtual List we have its initialized instance in variable (like myList
variable in example above) with helpful methods and properties:
Properties | |
---|---|
myList.items | Array with items |
myList.filteredItems | Array with filtered items (after using ".filterItems" method) |
myList.domCache | Object with cached dom items |
myList.params | Parameters passed on list initialization |
myList.listBlock | Dom7 instance of virtual list "list-block" container |
myList.pageContent | Dom7 instance of parent "page-content" container |
myList.currentFromIndex | Index number of currently first rendered item |
myList.currentToIndex | Index number of currently last rendered item |
myList.reachEnd | Boolean property. Equals true if the currently last rendered item is the last item of all specified items |
Methods | |
myList.filterItems(indexes); | Filter virtual list by passing array with indexes of items to show |
myList.resetFilter(); | Disable filter and display all items again |
myList.appendItem(item); | Append item to virtual list |
myList.appendItems(items); | Append array with items to virtual list |
myList.prependItem(item); | Prepend item to virtual list |
myList.prependItems(items); | Prepend array with items to virtual list |
myList.replaceItem(index, items); | Replace item at specified index with the new one |
myList.replaceAllItems(items); | Replace all items with arrays of new items |
myList.moveItem(oldIndex, newIndex); | Move virtual item from oldIndex to newIndex |
myList.insertItemBefore(index, item); | Insert new item before item with specified index |
myList.deleteItem(index); | Delete item at specified index |
myList.deleteItems(indexes); | Delete items at specified array of indexes |
myList.deleteAllItems(); | Delete all items |
myList.clearCache(); | Clear virtual list cached DOM elements |
myList.destroy(); | Destory initialized virtual list and detach all events |
myList.update(); | Update virtual list, including recalculation of list sizes and re-rendering of virtual list |
myList.scrollToItem(index); | Scroll Virtual List to specified item by its index number |
In the most simple case when we don't need to use templating for items (without template
and renderItem
parameters) and when we don't need much logic here, we may just pass items HTML layout in items
parameter:
var myList = myApp.virtualList('.list-block.virtual-list', {
// Array with plain HTML items
items: [
'<li class="item-content"><div clas="item-inner"><div class="item-title">Item 1</div></div></li>',
'<li class="item-content"><div clas="item-inner"><div class="item-title">Item 2</div></div></li>',
'<li class="item-content"><div clas="item-inner"><div class="item-title">Item 3</div></div></li>',
//...
'<li class="item-content"><div clas="item-inner"><div class="item-title">Item 1000</div></div></li>'
]
});
But in most cases we may need some logic that we can use for filtering and templating, or if we load items from some JSON data. In this case we may pass array with data objects in items
parameter and use Template7 template
parameter or custom render function using renderItem
parameter:
With Template7 template:
var myList = myApp.virtualList('.list-block.virtual-list', {
// Array with items data
items: [
{
title: 'Item 1',
picture: 'path/to/picture1.jpg'
},
{
title: 'Item 2',
picture: 'path/to/picture2.jpg'
},
// ...
{
title: 'Item 1000',
picture: 'path/to/picture1000.jpg'
},
],
// Template 7 template to render each item
template: '<li class="item-content">' +
'<div class="item-media"><img src="{{picture}}"></div>' +
'<div class="item-inner">' +
'<div class="item-title">{{title}}</div>' +
'</div>' +
'</li>'
});
With custom render function:
var myList = myApp.virtualList('.list-block.virtual-list', {
// Array with items data
items: [
{
title: 'Item 1',
picture: 'path/to/picture1.jpg'
},
{
title: 'Item 2',
picture: 'path/to/picture2.jpg'
},
// ...
{
title: 'Item 1000',
picture: 'path/to/picture1000.jpg'
},
],
// Custom render function to render item's HTML
renderItem: function (index, item) {
return '<li class="item-content">' +
'<div class="item-media"><img src="' + item.picture + '"></div>' +
'<div class="item-inner">' +
'<div class="item-title">' + item.title + '</div>' +
'</div>' +
'</li>';
}
});
If we use Virtual List with search bar we need to provide search function in parameters using searchAll
or searchByItem
parameters:
var myList = myApp.virtualList('.list-block.virtual-list', {
// Array with items data
items: [
{
title: 'Item 1',
picture: 'path/to/picture1.jpg'
},
{
title: 'Item 2',
picture: 'path/to/picture2.jpg'
},
// ...
{
title: 'Item 1000',
picture: 'path/to/picture1000.jpg'
},
],
// search all items, we need to return array with indexes of matched items
searchAll: function (query, items) {
var foundItems = [];
for (var i = 0; i < items.length; i++) {
// Check if title contains query string
if (items[i].title.indexOf(query.trim()) >= 0) foundItems.push(i);
}
// Return array with indexes of matched items
return foundItems;
}
});
The same but with searchByItem
parameter:
var myList = myApp.virtualList('.list-block.virtual-list', {
// Array with items data
items: [
{
title: 'Item 1',
picture: 'path/to/picture1.jpg'
},
{
title: 'Item 2',
picture: 'path/to/picture2.jpg'
},
// ...
{
title: 'Item 1000',
picture: 'path/to/picture1000.jpg'
},
],
// search item by item
searchByItem: function (query, index, item) {
// Check if title contains query string
if (item.title.indexOf(query.trim()) >= 0) {
return true; //item matches query
}
else {
return false; //item doesn't match
}
}
});
If not all of our items should be the same height we use dynamic height by specifying function in height
parameter instead of number:
var myList = myApp.virtualList('.list-block.virtual-list', {
// Array with items data
items: [
{
title: 'Item 1',
picture: 'path/to/picture1.jpg'
},
{
title: 'Item 2'
},
{
title: 'Item 3',
picture: 'path/to/picture3.jpg'
},
// ...
{
title: 'Item 1000'
},
],
// Item template
template: '...',
// Height function
height: function (item) {
if (item.picture) return 100; //item with picture is 100px height
else return 44; //item without picture is 44px height
}
});
Note that script will not actually set height on your items, so make sure that your items are really have specified height. You may also need to set it in CSS or using "style" attribute in template
or renderItem
parameters
Also note that dynamic height currently is not compatible with cols
parameter
If we need to add, remove, replace or move items in list we need to use Virtual List methods:
// Initialize List
var myList = myApp.virtualList('.list-block.virtual-list', {
// Array with items data
items: [
{
title: 'Item 1'
},
{
title: 'Item 2'
},
// ...
{
title: 'Item 1000'
}
],
// Item template
template: '...',
});
// Append Item
myList.appendItem({
title: 'Item 1001'
});
// Append multiple items when clicking on some button
$('.button.append-items').on('click', function () {
// Append multiple items by passing array with items
myList.appendItem([
{
title: 'Item 1002'
},
{
title: 'Item 1003'
},
{
title: 'Item 1004'
}
]);
});
// Replace First Item
myList.replaceItem(0, {
title: 'New Item 1'
});
// Show only first 10 items when clicking on button
$('.button.show-first-10').on('click', function () {
// We need to pass array with indexes of items to show
myList.filter([0, 1, 2, 3, 4, 5, 6, 7, 8, 9]);
});
// Reset filter
$('.button.reset-filter').on('click', function () {
myList.resetFilter();
});
// Insert new item before 1st and 2nd:
myList.insertItemBefore(1, {
title: 'Item 1.5'
});
Note that when you use methods to manipulate virtual list items you need to pass each item in the same format as you specify them in items parameter