2023-02-28 08:29:30 +00:00
|
|
|
<template>
|
|
|
|
<DocSectionText v-bind="$attrs">
|
|
|
|
<p>
|
|
|
|
Lazy mode is handy to deal with large datasets, instead of loading the entire data, small chunks of data is loaded by invoking corresponding callbacks everytime <i>paging</i>, <i>sorting</i> and <i>filtering</i> occurs. Sample below
|
|
|
|
imitates lazy loading data from a remote datasource using an in-memory list and timeouts to mimic network connection.
|
|
|
|
</p>
|
|
|
|
<p>
|
|
|
|
Enabling the <i>lazy</i> property and assigning the logical number of rows to <i>totalRecords</i> by doing a projection query are the key elements of the implementation so that paginator displays the UI assuming there are actually records
|
|
|
|
of totalRecords size although in reality they are not present on page, only the records that are displayed on the current page exist.
|
|
|
|
</p>
|
|
|
|
<p>In addition, only the root elements should be loaded, children can be loaded on demand using <i>nodeExpand</i> callback.</p>
|
|
|
|
</DocSectionText>
|
|
|
|
<div class="card">
|
|
|
|
<TreeTable :value="nodes" :lazy="true" :paginator="true" :rows="rows" :loading="loading" @nodeExpand="onExpand" @page="onPage" :totalRecords="totalRecords">
|
|
|
|
<Column field="name" header="Name" expander></Column>
|
|
|
|
<Column field="size" header="Size"></Column>
|
|
|
|
<Column field="type" header="Type"></Column>
|
|
|
|
</TreeTable>
|
|
|
|
</div>
|
|
|
|
<DocSectionCode :code="code" />
|
|
|
|
</template>
|
|
|
|
|
|
|
|
<script>
|
|
|
|
export default {
|
|
|
|
data() {
|
|
|
|
return {
|
|
|
|
nodes: null,
|
|
|
|
rows: 10,
|
|
|
|
loading: false,
|
|
|
|
totalRecords: 0,
|
|
|
|
code: {
|
2023-08-16 13:58:31 +00:00
|
|
|
basic: `<TreeTable :value="nodes" :lazy="true" :paginator="true" :rows="rows" :loading="loading"
|
2023-02-28 08:29:30 +00:00
|
|
|
@nodeExpand="onExpand" @page="onPage" :totalRecords="totalRecords">
|
|
|
|
<Column field="name" header="Name" expander></Column>
|
|
|
|
<Column field="size" header="Size"></Column>
|
|
|
|
<Column field="type" header="Type"></Column>
|
|
|
|
</TreeTable>`,
|
2023-08-16 13:58:31 +00:00
|
|
|
options: `<template>
|
2023-02-28 08:29:30 +00:00
|
|
|
<div class="card">
|
|
|
|
<TreeTable :value="nodes" :lazy="true" :paginator="true" :rows="rows" :loading="loading"
|
|
|
|
@nodeExpand="onExpand" @page="onPage" :totalRecords="totalRecords">
|
|
|
|
<Column field="name" header="Name" expander></Column>
|
|
|
|
<Column field="size" header="Size"></Column>
|
|
|
|
<Column field="type" header="Type"></Column>
|
|
|
|
</TreeTable>
|
|
|
|
</div>
|
|
|
|
</template>
|
|
|
|
|
|
|
|
<script>
|
|
|
|
export default {
|
|
|
|
data() {
|
|
|
|
return {
|
|
|
|
nodes: null,
|
|
|
|
rows: 10,
|
|
|
|
loading: false,
|
|
|
|
totalRecords: 0
|
|
|
|
};
|
|
|
|
},
|
|
|
|
mounted() {
|
|
|
|
this.loading = true;
|
|
|
|
|
|
|
|
setTimeout(() => {
|
|
|
|
this.loading = false;
|
|
|
|
this.nodes = this.loadNodes(0, this.rows);
|
|
|
|
this.totalRecords = 1000;
|
|
|
|
}, 1000);
|
|
|
|
},
|
|
|
|
methods: {
|
|
|
|
onExpand(node) {
|
|
|
|
if (!node.children) {
|
|
|
|
this.loading = true;
|
|
|
|
|
|
|
|
setTimeout(() => {
|
|
|
|
let lazyNode = { ...node };
|
|
|
|
|
|
|
|
lazyNode.children = [
|
|
|
|
{
|
|
|
|
data: {
|
|
|
|
name: lazyNode.data.name + ' - 0',
|
|
|
|
size: Math.floor(Math.random() * 1000) + 1 + 'kb',
|
|
|
|
type: 'File'
|
|
|
|
}
|
|
|
|
},
|
|
|
|
{
|
|
|
|
data: {
|
|
|
|
name: lazyNode.data.name + ' - 1',
|
|
|
|
size: Math.floor(Math.random() * 1000) + 1 + 'kb',
|
|
|
|
type: 'File'
|
|
|
|
}
|
|
|
|
}
|
|
|
|
];
|
|
|
|
|
|
|
|
let nodes = this.nodes.map((n) => {
|
|
|
|
if (n.key === node.key) {
|
|
|
|
n = lazyNode;
|
|
|
|
}
|
|
|
|
|
|
|
|
return n;
|
|
|
|
});
|
|
|
|
|
|
|
|
this.loading = false;
|
|
|
|
this.nodes = nodes;
|
|
|
|
}, 250);
|
|
|
|
}
|
|
|
|
},
|
|
|
|
onPage(event) {
|
|
|
|
this.loading = true;
|
|
|
|
|
|
|
|
//imitate delay of a backend call
|
|
|
|
setTimeout(() => {
|
|
|
|
this.loading = false;
|
|
|
|
this.nodes = this.loadNodes(event.first, this.rows);
|
|
|
|
}, 1000);
|
|
|
|
},
|
|
|
|
loadNodes(first, rows) {
|
|
|
|
let nodes = [];
|
|
|
|
|
|
|
|
for (let i = 0; i < rows; i++) {
|
|
|
|
let node = {
|
|
|
|
key: first + i,
|
|
|
|
data: {
|
|
|
|
name: 'Item ' + (first + i),
|
|
|
|
size: Math.floor(Math.random() * 1000) + 1 + 'kb',
|
|
|
|
type: 'Type ' + (first + i)
|
|
|
|
},
|
|
|
|
leaf: false
|
|
|
|
};
|
|
|
|
|
|
|
|
nodes.push(node);
|
|
|
|
}
|
|
|
|
|
|
|
|
return nodes;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
};
|
|
|
|
<\/script>`,
|
2023-08-16 13:58:31 +00:00
|
|
|
composition: `<template>
|
2023-02-28 08:29:30 +00:00
|
|
|
<div>
|
|
|
|
<TreeTable :value="nodes" :lazy="true" :paginator="true" :rows="rows" :loading="loading"
|
|
|
|
@nodeExpand="onExpand" @page="onPage" :totalRecords="totalRecords">
|
|
|
|
<Column field="name" header="Name" :expander="true"></Column>
|
|
|
|
<Column field="size" header="Size"></Column>
|
|
|
|
<Column field="type" header="Type"></Column>
|
|
|
|
</TreeTable>
|
|
|
|
</div>
|
|
|
|
</template>
|
|
|
|
|
|
|
|
<script setup>
|
|
|
|
import { ref, onMounted } from 'vue';
|
|
|
|
|
|
|
|
onMounted(() => {
|
|
|
|
loading.value = true;
|
|
|
|
|
|
|
|
setTimeout(() => {
|
|
|
|
loading.value = false;
|
|
|
|
nodes.value = loadNodes(0, rows.value);
|
|
|
|
totalRecords.value = 1000;
|
|
|
|
}, 1000);
|
|
|
|
});
|
|
|
|
|
|
|
|
const nodes = ref();
|
|
|
|
const rows = ref(10);
|
|
|
|
const loading = ref(false);
|
|
|
|
const totalRecords = ref(0);
|
|
|
|
const onExpand = (node) => {
|
|
|
|
if (!node.children) {
|
|
|
|
loading.value = true;
|
|
|
|
|
|
|
|
setTimeout(() => {
|
|
|
|
let lazyNode = {...node};
|
|
|
|
|
|
|
|
lazyNode.children = [
|
|
|
|
{
|
|
|
|
data: {
|
|
|
|
name: lazyNode.data.name + ' - 0',
|
|
|
|
size: Math.floor(Math.random() * 1000) + 1 + 'kb',
|
|
|
|
type: 'File'
|
|
|
|
},
|
|
|
|
},
|
|
|
|
{
|
|
|
|
data: {
|
|
|
|
name: lazyNode.data.name + ' - 1',
|
|
|
|
size: Math.floor(Math.random() * 1000) + 1 + 'kb',
|
|
|
|
type: 'File'
|
|
|
|
}
|
|
|
|
}
|
|
|
|
];
|
|
|
|
|
|
|
|
let newNodes = nodes.value.map(n => {
|
|
|
|
if (n.key === node.key) {
|
|
|
|
n = lazyNode;
|
|
|
|
}
|
|
|
|
|
|
|
|
return n;
|
|
|
|
});
|
|
|
|
|
|
|
|
loading.value = false;
|
|
|
|
nodes.value = newNodes;
|
|
|
|
}, 250);
|
|
|
|
}
|
|
|
|
};
|
|
|
|
const onPage = (event) => {
|
|
|
|
loading.value = true;
|
|
|
|
|
|
|
|
//imitate delay of a backend call
|
|
|
|
setTimeout(() => {
|
|
|
|
loading.value = false;
|
|
|
|
nodes.value = loadNodes(event.first, rows.value);
|
|
|
|
}, 1000);
|
|
|
|
};
|
|
|
|
const loadNodes = (first, rows) => {
|
|
|
|
let nodes = [];
|
|
|
|
|
|
|
|
for(let i = 0; i < rows; i++) {
|
|
|
|
let node = {
|
|
|
|
key: (first + i),
|
|
|
|
data: {
|
|
|
|
name: 'Item ' + (first + i),
|
|
|
|
size: Math.floor(Math.random() * 1000) + 1 + 'kb',
|
|
|
|
type: 'Type ' + (first + i)
|
|
|
|
},
|
|
|
|
leaf: false
|
|
|
|
};
|
|
|
|
|
|
|
|
nodes.push(node);
|
|
|
|
}
|
|
|
|
|
|
|
|
return nodes;
|
|
|
|
};
|
|
|
|
<\/script>`
|
|
|
|
}
|
|
|
|
};
|
|
|
|
},
|
|
|
|
mounted() {
|
|
|
|
this.loading = true;
|
|
|
|
|
|
|
|
setTimeout(() => {
|
|
|
|
this.loading = false;
|
|
|
|
this.nodes = this.loadNodes(0, this.rows);
|
|
|
|
this.totalRecords = 1000;
|
|
|
|
}, 1000);
|
|
|
|
},
|
|
|
|
methods: {
|
|
|
|
onExpand(node) {
|
|
|
|
if (!node.children) {
|
|
|
|
this.loading = true;
|
|
|
|
|
|
|
|
setTimeout(() => {
|
|
|
|
let lazyNode = { ...node };
|
|
|
|
|
|
|
|
lazyNode.children = [
|
|
|
|
{
|
|
|
|
data: {
|
|
|
|
name: lazyNode.data.name + ' - 0',
|
|
|
|
size: Math.floor(Math.random() * 1000) + 1 + 'kb',
|
|
|
|
type: 'File'
|
|
|
|
}
|
|
|
|
},
|
|
|
|
{
|
|
|
|
data: {
|
|
|
|
name: lazyNode.data.name + ' - 1',
|
|
|
|
size: Math.floor(Math.random() * 1000) + 1 + 'kb',
|
|
|
|
type: 'File'
|
|
|
|
}
|
|
|
|
}
|
|
|
|
];
|
|
|
|
|
|
|
|
let nodes = this.nodes.map((n) => {
|
|
|
|
if (n.key === node.key) {
|
|
|
|
n = lazyNode;
|
|
|
|
}
|
|
|
|
|
|
|
|
return n;
|
|
|
|
});
|
|
|
|
|
|
|
|
this.loading = false;
|
|
|
|
this.nodes = nodes;
|
|
|
|
}, 250);
|
|
|
|
}
|
|
|
|
},
|
|
|
|
onPage(event) {
|
|
|
|
this.loading = true;
|
|
|
|
|
|
|
|
//imitate delay of a backend call
|
|
|
|
setTimeout(() => {
|
|
|
|
this.loading = false;
|
|
|
|
this.nodes = this.loadNodes(event.first, this.rows);
|
|
|
|
}, 1000);
|
|
|
|
},
|
|
|
|
loadNodes(first, rows) {
|
|
|
|
let nodes = [];
|
|
|
|
|
|
|
|
for (let i = 0; i < rows; i++) {
|
|
|
|
let node = {
|
|
|
|
key: first + i,
|
|
|
|
data: {
|
|
|
|
name: 'Item ' + (first + i),
|
|
|
|
size: Math.floor(Math.random() * 1000) + 1 + 'kb',
|
|
|
|
type: 'Type ' + (first + i)
|
|
|
|
},
|
|
|
|
leaf: false
|
|
|
|
};
|
|
|
|
|
|
|
|
nodes.push(node);
|
|
|
|
}
|
|
|
|
|
|
|
|
return nodes;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
};
|
|
|
|
</script>
|