Has field
Display records that point back to the current record.
A Has field represents a reverse relation, such as the posts that point back to an author. The declaration identifies the related resource and the field that displays each related record.
API
fields.has(
name,
() => resource,
options: HasFieldOptions & { display: string | FieldBuilder }
)
| Option | Input | Result |
|---|---|---|
display |
string, field builder |
Displays through a target resource field. |
label |
string |
Sets the text shown for the field. |
description |
string |
Adds supporting text for the label. |
cardinality |
one, many |
Declares one or many reverse relations. |
configure(options) returns a configured clone. clone() returns an
independent copy with the same relation declaration and options. configure can replace the display field. The target resource stays fixed.
A Has field does not use a lookup target. A reverse relation is shown in a form but is not edited as one input.
Basic Has field
Pass the related records as an array. The display field reads each record.
import {
datalist,
defineResource,
fields,
} from '@backlit/sdk'
import { posts } from './posts.ts'
const authors = defineResource('authors', [
fields.has('posts', () => posts, {
label: 'Posts',
display: 'title',
}),
])
authors.view('detail', () =>
datalist({
posts: [
{ title: 'First post' },
{ title: 'Second post' },
],
}).setFields(authors.pick('posts'))
)
export default authorsimport { defineResource, fields } from '@backlit/sdk'
export const posts = defineResource('posts', [
fields.text('title'),
]){
"kind": "success",
"status": 200,
"node": {
"kind": "view",
"resource": "authors",
"name": "detail",
"slots": {
"content": [
{
"kind": "datalist",
"fields": [
{
"kind": "has",
"name": "posts",
"label": "Posts",
"display": {
"kind": "text",
"name": "title",
"label": ""
}
}
],
"data": {
"posts": [
"First post",
"Second post"
]
}
}
]
}
}
}Description
import {
datalist,
defineResource,
fields,
} from '@backlit/sdk'
import { posts } from './posts.ts'
const authors = defineResource('authors', [
fields.has('posts', () => posts, {
label: 'Posts',
display: 'title',
description: 'Posts written by this author.',
}),
])
authors.view('detail', () =>
datalist({
posts: [
{ title: 'First post' },
{ title: 'Second post' },
],
}).setFields(authors.pick('posts'))
)
export default authorsimport { defineResource, fields } from '@backlit/sdk'
export const posts = defineResource('posts', [
fields.text('title'),
]){
"kind": "success",
"status": 200,
"node": {
"kind": "view",
"resource": "authors",
"name": "detail",
"slots": {
"content": [
{
"kind": "datalist",
"fields": [
{
"kind": "has",
"name": "posts",
"description": "Posts written by this author.",
"label": "Posts",
"display": {
"kind": "text",
"name": "title",
"label": ""
}
}
],
"data": {
"posts": [
"First post",
"Second post"
]
}
}
]
}
}
}Display link
Configure the display field with link to make every related record link to
its target view.
import {
datalist,
defineResource,
fields,
linkTo,
} from '@backlit/sdk'
import { postDetail, posts } from './posts.ts'
const authors = defineResource('authors', [
fields.has('posts', () => posts, {
display: fields.text('title').configure({
link: linkTo(
() => postDetail,
(post: { id: number }) => [post.id]
),
}),
label: 'Posts',
}),
])
authors.view('detail', () =>
datalist({
posts: [
{ id: 10, title: 'First post' },
{ id: 11, title: 'Second post' },
],
}).setFields(authors.pick('posts'))
)
export default authorsimport { defineResource, fields } from '@backlit/sdk'
export const posts = defineResource('posts', [
fields.number('id'),
fields.text('title'),
])
export const postDetail = posts.view(
'detail',
['id'],
() => []
){
"kind": "success",
"status": 200,
"node": {
"kind": "view",
"resource": "authors",
"name": "detail",
"slots": {
"content": [
{
"kind": "datalist",
"fields": [
{
"kind": "has",
"name": "posts",
"label": "Posts",
"display": {
"kind": "text",
"name": "title",
"label": "",
"link": {
"kind": "link",
"resource": "posts",
"view": "detail"
}
}
}
],
"data": {
"posts": [
{
"value": "First post",
"args": [
10
]
},
{
"value": "Second post",
"args": [
11
]
}
]
}
}
]
}
}
}Cardinality
Cardinality declares whether one or many records point back. Has data is supplied as a related record set.
import {
datalist,
defineResource,
fields,
} from '@backlit/sdk'
import { posts } from './posts.ts'
const authors = defineResource('authors', [
fields.has('featuredPost', () => posts, {
label: 'Featured post',
display: 'title',
cardinality: 'one',
}),
fields.has('posts', () => posts, {
label: 'Posts',
display: 'title',
cardinality: 'many',
}),
])
authors.view('detail', () =>
datalist({
featuredPost: [{ title: 'First post' }],
posts: [
{ title: 'First post' },
{ title: 'Second post' },
],
}).setFields(authors.pick('featuredPost', 'posts'))
)
export default authorsimport { defineResource, fields } from '@backlit/sdk'
export const posts = defineResource('posts', [
fields.text('title'),
]){
"kind": "success",
"status": 200,
"node": {
"kind": "view",
"resource": "authors",
"name": "detail",
"slots": {
"content": [
{
"kind": "datalist",
"fields": [
{
"kind": "has",
"name": "featuredPost",
"cardinality": "one",
"label": "Featured post",
"display": {
"kind": "text",
"name": "title",
"label": ""
}
},
{
"kind": "has",
"name": "posts",
"cardinality": "many",
"label": "Posts",
"display": {
"kind": "text",
"name": "title",
"label": ""
}
}
],
"data": {
"featuredPost": [
"First post"
],
"posts": [
"First post",
"Second post"
]
}
}
]
}
}
}Clone
Use configure to add a link for one context without changing the
shared field.
import {
datalist,
defineResource,
fields,
linkTo,
} from '@backlit/sdk'
import { postDetail, posts } from './posts.ts'
const relatedPosts = fields.has('posts', () => posts, {
label: 'Posts',
display: 'title',
})
const authors = defineResource('authors', [
relatedPosts.configure({
display: fields.text('title').configure({
link: linkTo(
() => postDetail,
(post: { id: number }) => [post.id]
),
}),
}),
])
authors.view('detail', () =>
datalist({
posts: [{ id: 10, title: 'First post' }],
}).setFields(authors.pick('posts'))
)
export default authorsimport { defineResource, fields } from '@backlit/sdk'
export const posts = defineResource('posts', [
fields.number('id'),
fields.text('title'),
])
export const postDetail = posts.view(
'detail',
['id'],
() => []
){
"kind": "success",
"status": 200,
"node": {
"kind": "view",
"resource": "authors",
"name": "detail",
"slots": {
"content": [
{
"kind": "datalist",
"fields": [
{
"kind": "has",
"name": "posts",
"label": "Posts",
"display": {
"kind": "text",
"name": "title",
"label": "",
"link": {
"kind": "link",
"resource": "posts",
"view": "detail"
}
}
}
],
"data": {
"posts": [
{
"value": "First post",
"args": [
10
]
}
]
}
}
]
}
}
}All options
A Has field can use a linked display field, metadata, and many cardinality together.
import {
datalist,
defineResource,
fields,
linkTo,
} from '@backlit/sdk'
import { postDetail, posts } from './posts.ts'
const authors = defineResource('authors', [
fields.has('posts', () => posts, {
display: fields.text('title').configure({
link: linkTo(
() => postDetail,
(post: { id: number }) => [post.id]
),
}),
label: 'Posts',
description: 'Posts written by this author.',
cardinality: 'many',
}),
])
authors.view('detail', () =>
datalist({
posts: [
{ id: 10, title: 'First post' },
{ id: 11, title: 'Second post' },
],
}).setFields(authors.pick('posts'))
)
export default authorsimport { defineResource, fields } from '@backlit/sdk'
export const posts = defineResource('posts', [
fields.number('id'),
fields.text('title'),
])
export const postDetail = posts.view(
'detail',
['id'],
() => []
){
"kind": "success",
"status": 200,
"node": {
"kind": "view",
"resource": "authors",
"name": "detail",
"slots": {
"content": [
{
"kind": "datalist",
"fields": [
{
"kind": "has",
"name": "posts",
"description": "Posts written by this author.",
"cardinality": "many",
"label": "Posts",
"display": {
"kind": "text",
"name": "title",
"label": "",
"link": {
"kind": "link",
"resource": "posts",
"view": "detail"
}
}
}
],
"data": {
"posts": [
{
"value": "First post",
"args": [
10
]
},
{
"value": "Second post",
"args": [
11
]
}
]
}
}
]
}
}
}Supply an array of related records for both cardinalities. Use an empty array
for no related records. cardinality: 'one' changes the declaration; it does
not change the array input that the current Has builder reads.