useList ​

useList fetches a page of documents of a DocType, with filters, sorting, paging and write members. Its rows stay in sync with useDoc.

Basic example ​

vue
<template>
  <div v-for="todo in todos.data" :key="todo.name">
    {{ todo.description }} ({{ todo.status }})
  </div>
  <Button v-if="todos.hasNextPage" @click="todos.next()">Load more</Button>
</template>

<script setup>
import { useList } from 'frappe-ui'

const todos = useList({
  doctype: 'ToDo',
  fields: ['name', 'description', 'status'],
  orderBy: 'creation desc',
  limit: 20,
})
</script>

next() fetches the next page and adds its rows to the end of data.

Filter the list ​

Give each field a value to match, or an [operator, value] pair. When a ref or getter in filters changes, the list fetches again:

vue
<script setup>
import { ref } from 'vue'
import { useList } from 'frappe-ui'

const status = ref('Open')
const todos = useList({
  doctype: 'ToDo',
  filters: {
    status,
    priority: ['in', ['High', 'Urgent']],
    description: ['like', 'deploy'],
  },
})
</script>

A like value without % is wrapped in % on both sides, and an empty like value is left out.

Update a row ​

setValue.isLoading(name) shows a loading state on one row while it saves:

vue
<script setup>
import { useList } from 'frappe-ui'

const todos = useList({ doctype: 'ToDo', fields: ['name', 'description'] })

async function close(name) {
  await todos.setValue.submit({ name, status: 'Closed' })
}
</script>

<template>
  <div v-for="todo in todos.data" :key="todo.name">
    {{ todo.description }}
    <Button
      :loading="todos.setValue.isLoading(todo.name)"
      @click="close(todo.name)"
    >
      Close
    </Button>
  </div>
</template>

Each submit sends its own request, so two rows can save or delete at the same time.

Options ​

NameTypeDefaultDescription
doctypestringrequiredThe DocType to list.
fieldsArrayserver defaultFields per row: 'name', '*', 'field as alias', 'link_field.fieldname', or a child table such as { items: ['item_code', 'qty'] }.
filtersMaybeRefOrGetter<Filters>Field names mapped to a value to match or an [operator, value] pair. Values can be refs or getters.
orderByMaybeRefOrGetter<OrderBy>'<field> asc' or '<field> desc'.
startnumber0The offset of the first row.
limitnumber20The page size.
groupBystringA field to group rows by.
parentstringFor a child table DocType, the parent DocType.
debugbooleanfalseAsks the server for debug output and logs it to the console.
immediatebooleantrueFetches the first page when useList runs.
refetchbooleantrueFetches again when filters or orderBy change, and after each successful write.
initialDataT[]The rows to show before the first response, in the shape the server sends. They go through transform, the same as a response.
cacheKeyCacheKeyA string or an array. Saves the rows in IndexedDB and shows them at once on the next useList with this key. Each user has their own saved rows: see One cache per user.
staleOnErrorbooleanfalseWith cacheKey, a failed fetch keeps showing the cached rows. A Frappe error response still clears them.
transform(rows: T[]) => T[]Changes the rows before they go into data. It gets every row loaded so far, from all pages, and runs again after each new page or row change. It gets a copy, so it may change the rows in place.
onSuccess(rows: T[]) => voidCalled with all loaded rows after each successful fetch.
onError(error: Error) => voidCalled with the error after each failed fetch.
urlstring/api/v2/document/<doctype>Replaces the URL of the fetch. The list params are still added.
baseUrlstring''A prefix for every request URL.

Return value ​

NameTypeDescription
dataT[] | nullThe rows loaded so far, or null before the first response.
errorError | nullThe error from the last fetch.
loadingbooleantrue while a fetch is in flight. Also available as isFetching.
isFinishedbooleantrue once the current fetch has settled, with or without an error.
hasNextPagebooleantrue if the server has more rows after the last page.
hasPreviousPagebooleantrue if start is above 0.
startnumberThe offset of the current page.
limitnumberThe page size.
urlstringThe full request URL.
canAbortbooleantrue while a fetch that can be aborted is in flight.
abortedbooleantrue if the last fetch was aborted.
reload()() => PromiseFetches again from start. Resolves even if it fails, so check error. Also available as execute() and fetch().
abort()() => voidAborts the fetch in flight.
next()() => voidMoves start forward one page and fetches it.
previous()() => voidMoves start back one page and fetches it.
updateRow(doc)(doc) => voidChanges the row with the same name in data, without a request. Only fields the row has change. Pass values as the server sends them: transform runs again on the row.
removeRow(name)(name: string) => voidRemoves the row with this name from data, without a request.
insertwrite memberinsert.submit(values) creates a document. insert.isLoading() takes no argument.
setValuewrite membersetValue.submit({ name, ...values }) saves fields of one document. setValue.isLoading(name) checks one row.
deletewrite memberdelete.submit({ name }) deletes one document. delete.isLoading(name) checks one row.

A write member has data, error, loading, submit(params) and isLoading(...). loading is true while any submit of that member is in flight. data and error belong to the submit that started last. With refetch: true, a successful write fetches the list again.

Errors ​

insert, setValue and delete reject when they fail, so catch the error. reload() resolves and sets error. See Errors for the rule and the error classes.

js
try {
  await todos.delete.submit({ name })
} catch (error) {
  toast.error(error.message)
}

Shared cache ​

Rows of a useList and documents of a useDoc with the same doctype and name stay in sync. A save or delete through one updates the other, and every other useList of that DocType.