Skip to content
Backlit
Esc
navigateopen⌘Jpreview
On this page

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 authors
{
  "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 authors
{
  "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"
            ]
          }
        }
      ]
    }
  }
}

Configure the display field with link to make every related record link to its target view.

{
  "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 authors
{
  "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 authors
{
  "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 authors
{
  "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.

Was this page helpful?