Skip to content

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 your mono.config.ts instead, pass configBaseUrl: '<entry>' (see Data Fetching).
  • url โ€” the entity path appended to the base URL.
  • options โ€” devextreme DataSource options: select, paginate, pageSize, sort, filter, โ€ฆ The entity key defaults to Id, 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 with table.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>