Components that need data (select, datatable, charts) support 4 levels of data supply. All levels available simultaneously — pick what fits, or combine.
Data directly in the prop. No fetch.
<bc-field-select name="status" options='[{"label":"Active","value":"active"},{"label":"Inactive","value":"inactive"}]' />
<bc-datatable columns='[...]' data='[{"id":1,"name":"John"}]' />Component fetches data via native fetch(). Auto-detects response format.
<bc-field-select name="city" data-source="/api/cities" />
<bc-datatable columns='[...]' data-source="/api/users" server-side />Supported response formats (auto-detected):
{ data: [...] }{ results: [...] }{ items: [...] }{ records: [...] }{ rows: [...] }[...](plain array)
Total count detected from: total, total_count, totalCount, count, total_records.
Override auto-detection globally:
BcSetup.configure({
responseTransformer: (res) => ({ data: res.payload, total: res.meta.count })
});Modify request before fetch, or transform response after fetch.
<bc-datatable id="t" data-source="/api/users" server-side />
<script>
document.getElementById('t').addEventListener('lcBeforeFetch', (e) => {
e.detail.headers['X-Custom'] = 'value';
e.detail.url = e.detail.url + '&extra=param';
});
document.getElementById('t').addEventListener('lcAfterFetch', (e) => {
e.detail.data = e.detail.response.items.map(i => ({ id: i.ID, name: i.FullName }));
e.detail.total = e.detail.response.totalCount;
});
</script>Full control. Set a JavaScript function on the element.
<bc-datatable id="t" columns='[...]' />
<script>
document.getElementById('t').dataFetcher = async (params) => {
// params = { page, pageSize, sort, filters, search }
const token = await getAuthToken();
const res = await fetch('https://my-api.com/data', {
method: 'POST',
headers: { 'Authorization': `Bearer ${token}` },
body: JSON.stringify({ offset: (params.page - 1) * params.pageSize, limit: params.pageSize })
});
const json = await res.json();
return { data: json.records, total: json.meta.total_count };
};
</script>For select-family components:
document.getElementById('citySelect').optionsFetcher = async (query, params) => {
// query = search text, params = { dependValues: { province: 'jabar' } }
const res = await fetch(`/api/cities?q=${query}&prov=${params.dependValues?.province || ''}`);
return await res.json();
};1. dataFetcher/optionsFetcher (JS property) → Level 4
2. lcBeforeFetch/lcAfterFetch listeners → Level 3 (with dataSource)
3. dataSource prop → Level 2 (native fetch)
4. data/options prop → Level 1 (local)
5. model prop + BitCode api-client → BitCode fallback
6. nothing → empty state
All fetch requests automatically include headers from BcSetup.configure():
BcSetup.configure({
baseUrl: '/api',
auth: { type: 'bearer', token: () => localStorage.getItem('jwt') },
headers: { 'X-Tenant': 'company-a' }
});Per-component custom headers via fetch-headers prop:
<bc-datatable data-source="/api/data" fetch-headers='{"X-Custom":"value"}' />Use depend-on + data-source with {field} placeholders:
<bc-field-select name="province" options='[...]' />
<bc-field-select name="city" depend-on="province" data-source="/api/cities?province={province}" />
<bc-field-select name="district" depend-on="city" data-source="/api/districts?city={city}" />When province changes, city auto-fetches new options and clears its value. Cascades further to district.