Skip to content
Backlit
Esc
navigateopen⌘Jpreview
On this page

Filter binding and placement

Bind, read, and display filters in a view or zone.

A filter declaration has no URL namespace until you bind it to a view or zone. A view filter uses f[name]. A zone filter uses f[zone][name].

Use the same binding for two operations:

  • Pass its owner to ctx.parse to read typed values.
  • Pass it to section.setFilters or panel.setFilters to display controls.

View binding

Pass a filter bar through the view options. The resolver receives the binding as view.state.filters.

import {
  defineFilters,
  defineResource,
  filters,
  section,
} from '@backlit/sdk'

const orders = defineResource('orders', [])
const orderFilters = defineFilters([
  filters.text('search').setLabel('Search orders'),
])

orders.view(
  'list',
  { filters: orderFilters },
  (_ctx, view) =>
    section('Orders').setFilters(view.state.filters)
)

export default orders
{
  "kind": "success",
  "status": 200,
  "node": {
    "kind": "view",
    "resource": "orders",
    "name": "list",
    "slots": {
      "content": [
        {
          "kind": "section",
          "title": "Orders",
          "slots": {
            "content": [],
            "filters": {
              "kind": "filters",
              "resource": "orders",
              "view": "list",
              "keyword": "f",
              "definesResult": true,
              "dependsOnResult": false,
              "filters": [
                {
                  "kind": "text",
                  "name": "search",
                  "label": "Search orders"
                }
              ]
            }
          }
        }
      ]
    }
  }
}

Read view filters

Call ctx.parse(view).filters. The result has one typed property for each declared filter. A missing or invalid value is undefined.

import {
  callout,
  defineFilters,
  defineResource,
  filters,
  section,
} from '@backlit/sdk'

const orders = defineResource('orders', [])
const orderFilters = defineFilters([
  filters.text('search').setLabel('Search orders'),
  filters.toggle('paid').setLabel('Paid'),
])

orders.view(
  'list',
  { filters: orderFilters },
  (ctx, view) => {
    const { search, paid } = ctx.parse(view).filters

    return section('Orders')
      .setFilters(view.state.filters)
      .setContent([
        callout(
          `Search: ${search ?? 'all'}; paid: ${paid ?? 'all'}`
        ),
      ])
  }
)

export default orders
{
  "kind": "success",
  "status": 200,
  "node": {
    "kind": "view",
    "resource": "orders",
    "name": "list",
    "slots": {
      "content": [
        {
          "kind": "section",
          "title": "Orders",
          "slots": {
            "content": [
              {
                "kind": "callout",
                "text": "Search: all; paid: all"
              }
            ],
            "filters": {
              "kind": "filters",
              "resource": "orders",
              "view": "list",
              "keyword": "f",
              "definesResult": true,
              "dependsOnResult": false,
              "filters": [
                {
                  "kind": "text",
                  "name": "search",
                  "label": "Search orders"
                },
                {
                  "kind": "toggle",
                  "name": "paid",
                  "label": "Paid"
                }
              ]
            }
          }
        }
      ]
    }
  }
}

Zone binding

Pass a filter bar through the zone options. Place zone.state.filters inside the zone. A control change then requests only that zone.

import {
  defineFilters,
  defineResource,
  filters,
  section,
  table,
  zone,
} from '@backlit/sdk'

const orders = defineResource('orders', [])
const activityFilters = defineFilters([
  filters.text('search').setLabel('Search activity'),
])

orders.view('detail', () =>
  zone(
    'activity',
    { filters: activityFilters },
    (_ctx, currentZone) =>
      section('Activity')
        .setFilters(currentZone.state.filters)
        .setContent([table([]).setFields([])])
  )
)

export default orders
{
  "kind": "success",
  "status": 200,
  "node": {
    "kind": "view",
    "resource": "orders",
    "name": "detail",
    "slots": {
      "content": [
        {
          "kind": "zone",
          "name": "activity",
          "resource": "orders",
          "view": "detail",
          "slots": {
            "content": [
              {
                "kind": "section",
                "title": "Activity",
                "slots": {
                  "content": [
                    {
                      "kind": "table",
                      "fields": [],
                      "data": []
                    }
                  ],
                  "filters": {
                    "kind": "filters",
                    "resource": "orders",
                    "view": "detail",
                    "zone": "activity",
                    "keyword": "f",
                    "definesResult": true,
                    "dependsOnResult": false,
                    "filters": [
                      {
                        "kind": "text",
                        "name": "search",
                        "label": "Search activity"
                      }
                    ]
                  }
                }
              }
            ]
          }
        }
      ]
    }
  }
}

Read zone filters

Call ctx.parse(zone).filters. Backlit reads values from that zone scope.

import {
  callout,
  defineFilters,
  defineResource,
  filters,
  section,
  zone,
} from '@backlit/sdk'

const orders = defineResource('orders', [])
const activityFilters = defineFilters([
  filters.text('search').setLabel('Search activity'),
])

orders.view('detail', () =>
  zone(
    'activity',
    { filters: activityFilters },
    (ctx, currentZone) => {
      const { search } = ctx.parse(currentZone).filters

      return section('Activity')
        .setFilters(currentZone.state.filters)
        .setContent([
          callout(`Search: ${search ?? 'all activity'}`),
        ])
    }
  )
)

export default orders
{
  "kind": "success",
  "status": 200,
  "node": {
    "kind": "view",
    "resource": "orders",
    "name": "detail",
    "slots": {
      "content": [
        {
          "kind": "zone",
          "name": "activity",
          "resource": "orders",
          "view": "detail",
          "slots": {
            "content": [
              {
                "kind": "section",
                "title": "Activity",
                "slots": {
                  "content": [
                    {
                      "kind": "callout",
                      "text": "Search: all activity"
                    }
                  ],
                  "filters": {
                    "kind": "filters",
                    "resource": "orders",
                    "view": "detail",
                    "zone": "activity",
                    "keyword": "f",
                    "definesResult": true,
                    "dependsOnResult": false,
                    "filters": [
                      {
                        "kind": "text",
                        "name": "search",
                        "label": "Search activity"
                      }
                    ]
                  }
                }
              }
            ]
          }
        }
      ]
    }
  }
}

Place filters in a section

A filter bar is not a content block. A section has a separate slot for it.

import {
  defineFilters,
  defineResource,
  filters,
  section,
} from '@backlit/sdk'

const orders = defineResource('orders', [])
const orderFilters = defineFilters([
  filters.text('search').setLabel('Search orders'),
])

orders.view(
  'list',
  { filters: orderFilters },
  (_ctx, view) =>
    section('Orders')
      .setFilters(view.state.filters)
)

export default orders
{
  "kind": "success",
  "status": 200,
  "node": {
    "kind": "view",
    "resource": "orders",
    "name": "list",
    "slots": {
      "content": [
        {
          "kind": "section",
          "title": "Orders",
          "slots": {
            "content": [],
            "filters": {
              "kind": "filters",
              "resource": "orders",
              "view": "list",
              "keyword": "f",
              "definesResult": true,
              "dependsOnResult": false,
              "filters": [
                {
                  "kind": "text",
                  "name": "search",
                  "label": "Search orders"
                }
              ]
            }
          }
        }
      ]
    }
  }
}

Place filters in a panel

A panel has the same separate filter slot.

import {
  defineFilters,
  defineResource,
  filters,
  panel,
} from '@backlit/sdk'

const orders = defineResource('orders', [])
const orderFilters = defineFilters([
  filters.text('search').setLabel('Search orders'),
])

orders.view(
  'list',
  { filters: orderFilters },
  (_ctx, view) =>
    panel([])
      .setTitle('Orders')
      .setFilters(view.state.filters)
)

export default orders
{
  "kind": "success",
  "status": 200,
  "node": {
    "kind": "view",
    "resource": "orders",
    "name": "list",
    "slots": {
      "content": [
        {
          "kind": "panel",
          "title": "Orders",
          "slots": {
            "content": [],
            "filters": {
              "kind": "filters",
              "resource": "orders",
              "view": "list",
              "keyword": "f",
              "definesResult": true,
              "dependsOnResult": false,
              "filters": [
                {
                  "kind": "text",
                  "name": "search",
                  "label": "Search orders"
                }
              ]
            }
          }
        }
      ]
    }
  }
}

Was this page helpful?