DataSource โ
What is a DataSource? โ
A DataSource is a live handle to a remote OData endpoint. Instead of fetching rows into a plain array, you hand a component a DataSource and it loads on demand โ pulling one page at a time and exposing paging, filtering and sorting.
The key idea: a DataSource is reactive. It emits a changed event whenever its data updates, and the bound component re-renders automatically. So you can filter or sort the DataSource from anywhere โ even outside the component โ and the UI stays in sync without re-binding.
Use it when the data lives on a server and you want the component to page / search / filter against it, rather than loading everything up front.
Create one with monoCreateFetcher โ
monoCreateFetcher builds a DataSource for an OData endpoint. Import it at the top level and call .response({ options }) โ you get back a dataSource (plus data, statusCode, error).
ts
import { monoCreateFetcher } from 'mono-utils/fetching'
const { dataSource } = await monoCreateFetcher({
baseUrl: 'https://dev-ppl-project.phoenix-squad.eu.org/odata',
url: '/DTO_Departmen',
}).response({
options: {
select: ['Id', 'Code', 'Nama'],
paginate: true,
pageSize: 10,
},
})baseUrlโ the OData root. To resolve it from yourmono.config.tsinstead, passconfigBaseUrl: '<entry>'(see Data Fetching).urlโ the entity path appended to the base URL.optionsโ devextreme DataSource options:select,paginate,pageSize,sort,filter, โฆ The entitykeydefaults toId, so you usually don't need to set it.
Example: bind it to mono-select โ
Create the DataSource in onMounted, then bind it with :data-source.prop. Use key-value / display-value to map the server fields, and load-more="scroll" to page the source as the user scrolls.
vue
<script setup lang="ts">
import { ref, onMounted } from 'vue'
import { monoCreateFetcher } from 'mono-utils/fetching'
const ds = ref<any>(null)
const selected = ref<unknown>(null)
onMounted(async () => {
const { dataSource } = await monoCreateFetcher({
baseUrl: 'https://dev-ppl-project.phoenix-squad.eu.org/odata',
url: '/DTO_Departmen',
}).response({
options: {
select: ['Id', 'Code', 'Nama'],
paginate: true,
pageSize: 10,
},
})
ds.value = dataSource
})
const onChange = (e: any) => {
selected.value = e.detail.currentValue
}
// Filter the source from anywhere โ the bound component updates through the
// DataSource's "changed" event, no re-binding needed.
const filterMkt = async () => {
ds.value?.filter(["contains(Code, 'MKT')"])
await ds.value?.load()
}
</script>
<template>
<mono-select
:data-source.prop="ds"
load-more="scroll"
key-value="Code"
display-value="Nama"
label="Department"
placeholder="Pick a department"
@mno-change="onChange"
></mono-select>
</template>Why :data-source.prop?
A DataSource is an object. On a custom element, Vue would stringify a plain :data-source binding into an attribute โ so you must use the .prop modifier to pass it as a real DOM property.
Need one record? load({ take: 1 }), never byKey() โ
To pull a single row from a DataSource, query it through load โ add a filter if you're matching on a field:
ts
const [first] = await ds.value.load({ take: 1 })
// matching a specific row:
const [match] = await ds.value.load({ filter: ['Id', '=', id], take: 1 })Don't use ds.value.store().byKey(id)
Once a DataSource is bound to a component, byKey reads from / caches against the data already loaded into that DataSource โ so it can hand you a stale, cached row (or undefined for one that was never paged in) instead of a fresh result. Always use load({ take: 1 }) (with a filter when needed); it goes through the source's normal query path and returns live data.
Components that accept a DataSource โ
The same dataSource works across these components:
mono-select โ
A single-value picker. Bind :data-source.prop, map fields with key-value / display-value, and page with load-more="scroll" (or "button"). See Select.
vue
<mono-select :data-source.prop="ds" load-more="scroll"
key-value="Code" display-value="Nama"></mono-select>mono-tag-input โ
Multi-value version โ same props, plus :immediate.prop="true" to load on mount. See Tag input.
vue
<mono-tag-input :data-source.prop="ds" :immediate.prop="true"
load-more="scroll" key-value="Id" display-value="Nama"></mono-tag-input>mono-table โ
A native table. Wrap the DataSource in a monoDataGrid controller, then bind the controls with :data-grid.prop. See Table.
No remote data? Pass a plain array straight to
monoDataGridโmonoDataGrid(rows, { pageSize: 10, searchExpr: ['Code', 'Nama'] })โ and it pages, searches and sorts in memory. Swap rows later withtable.setData(next).
vue
<script setup lang="ts">
import { monoDataGrid } from 'mono-helper'
const table = monoDataGrid(null, { searchExpr: ['Code', 'Nama'] })
// after creating `dataSource`: table.bind(dataSource); await table.load()
</script>
<template>
<mono-table-search :data-grid.prop="table"></mono-table-search>
<!-- render your <table> from table.items โฆ -->
<mono-table-paging :data-grid.prop="table"></mono-table-paging>
</template>