Lookup fields - Working with writable views
Mia-Platform CRUD Service allows to create writable views.
Views are virtual collections that encapsulate the results derived from aggregation pipelines. Their primary function revolves around presenting data obtained from one collection within the contextual framework of a main collection, which is referred to as the "source". Normally, views are read-only, but since version 6.9.0 of the CRUD Service
, editing a view will automatically reflect changes to the original collection.
"Lookup fields" are those fields within views that reference data from a collection different to the original one. Components such as the Dynamic Form Modal are geared to work with such fields.
Lookup fields can be configured in the data-schema by defining fields of type object
or array
and format lookup
.
The Dynamic Form Modal, Dynamic Form Drawer, Dynamic Form Card components render these as select fields, for which options are fetched using the /lookup
route provided by CRUD Service
views.
Each option fetched like this is expected to be an object, and should have at least a label
field, which is used as display value inside the form, and a value
field which is used as unique identifier for such option.
Setting up lookup fields using the Crud Lookup Client in conjunction with one between Dynamic Form Modal or Dynamic Form Drawer or Dynamic Form Card is deprecated since version 1.4.0 of Back-Kit components.\ Documentation on previous way of configuring lookup fields is available here.
Lookup fields display in the Table
Table normally shows lookup array fields cells as a placeholder, holding a counter of the elements in the array.
However, if internal content is meant to be shown in-place, it is possible to join
its values and print it as a string.
This is achieved by specifying a joinDelimiter
key in the visualization options of the data-schema. An empty string is allowed.
The label
s of the array entries are joined with the specified string in joinDelimiter
.
{
"visualizationOptions": {
"joinDelimiter": "<delimiter>"
}
}
Lookup fields of type object are also displayed as a placeholder by default in table cells.
Property template
in the visualization options of the data-schema can be used to specify a custom visualization. For instance:
{
"visualizationOptions": {
"joinDelimiter": "{{label}}"
}
}
For an example, see below.
Migrating to writable views from previous lookups
Starting from version 1.4.0 of Back-Kit, lookup fields should be handled through CRUD Service feature of writable views.
In particular, the Dynamic Form Modal, Drawer, Card components do not listen to events triggered by the Crud Lookup Client, but rather fetch lookup options directly by calling the /lookup
route, that the Crud Service makes available for writable views.
The Crud Lookup Client component is therefore deprecated, as well as:
- the Form Modal, which should be replaced by the Dynamic Form Modal,
- the Form Drawer, which should be replaced by the Dynamic Form Drawer,
- the Form Card, which should be replaced by the Dynamic Form Card.
Data-schema key lookupOptions
is also deprecated, and ignored by the new form components.
The Dynamic Form Modal, Drawer, Card can be configured in a way to cover features that were previously configured using lookupOptions
.
lookupQueries
lookupQueries
should not be specified insidelookupOptions
in the data-schema, but rather as a property of the form component, which maps each lookup field to additional queries to append to the call to fetch options.An example is available showing how to configure the property
lookupQueries
of the Dynamic Form Modal.lookupDeps
Property
lookupDeps
oflookupOptions
is used to specify a dependency between a lookup field and other fields within the form. The Dynamic Form Modal, Drawer, Card, instead, handle dependencies among fields through propertiesconditionalOptions
andconditionalValues
.An example is available showing how to use properties
conditionalValues
andlookupQueries
of the Dynamic Form Modal to set up lookup fields that depend on other fields of the form.
Examples
Example: Submitting writable views with a form component
The following example shows a configuration of the Dynamic Form Modal designed to interact with writable views:
{
"tag": "bk-dynamic-form-modal",
"properties": {
"dataSchema": {
"type": "object",
"properties": {
"name": {"type": "string"},
"rider": {"type": "object", "format": "lookup"}
}
},
"basePath": "/orders-view"
}
}
- being "rider" an
object
field withlookup
format, it is rendered as a select field inside the form - options for "rider" select field are dynamically fetched from
/orders-view/lookup/rider
Example: Showing lookup fields in the Table
Specifying a joinDelimiter
key in the data-schema's visualization options of a lookup array field causes the Table to show the content of the field in-place inside the corresponding cell.
A Table configured like:
{
"tag": "bk-table",
"properties": {
"dataSchema": {
"type": "object",
"properties": {
"name": {
"type": "string"
},
"dishes": {
"type": "array",
"format": "lookup"
},
"riders": {
"type": "array",
"format": "lookup",
"visualizationOptions": {
"joinDelimiter": ", "
}
},
"customer": {
"type": "object",
"format": "lookup",
"visualizationOptions": {
"template": "{{label}}"
}
}
}
}
}
}
with data like:
[
{
"name": "Sarah",
"dishes": [
{"value": "id-dish-1", "label": "Omelette"},
{"value": "id-dish-9", "label": "Veggie Burger"},
],
"riders": [
{"value": "id-rider-1", "label": "Alejandro"},
{"value": "id-rider-2", "label": "Susanna"},
],
"customer": {
"value":"id-customer-1", "label": "Marco"
}
},
{
"name": "Bruce",
"dishes": [
{"value": "id-dish-7", "label": "Hamburger"},
{"value": "id-dish-5", "label": "Coconut"},
{"value": "id-dish-10", "label": "Cheesecake"},
],
"riders": [
{"value": "id-rider-4", "label": "Simon"}
],
"customer": {
"value":"id-customer-12", "label": "Kevin"
}
}
]
renders a table which can be represented by an array like:
[
["name", "dishes", "riders", "customer"], // header
["Sarah", "2 Elements", "Alejandro, Susanna", "Marco"],
["Bruce", "3 Elements", "Simon", "Kevin"]
]
Example: Setting up extra queries to fetch lookup options
A Dynamic Form Modal configured like the following
{
"tag": "bk-dynamic-form-modal",
"properties": {
"dataSchema": {
"type": "object",
"properties": {
"dishes": {"type": "array", "format": "lookup"}
}
},
"basePath": "/orders",
"lookupQueries": {
"dishes": {
"calories": {
"$lt": 300
}
}
}
}
}
fetches options for field "dishes" from orders/lookup/dishes
with the additional condition that "calories" field of dishes collection should be lower than 300, expressed in the query parameters of the request.
Dynamic queries are also available:
{
"tag": "bk-dynamic-form-modal",
"properties": {
"dataSchema": {
"type": "object",
"properties": {
"maxCalories": {"type": "number"},
"dishes": {"type": "array", "format": "lookup"}
}
},
"basePath": "/orders",
"lookupQueries": {
"dishes": {
"calories": {
"$lt": "{{rawObject maxCalories}}" // rawObject can be used to prevent numeric values from being stringified
}
}
}
}
}
in this case, form field "maxCalories" is used to dynamically compute the additional query to use when fetching options for "dishes" lookup field.
In the previous example, rawObject
helper is used to avoid numeric values from being stringified
Example: Specifying lookup dependencies
{
"tag": "bk-dynamic-form-modal",
"properties": {
"basePath": "/orders",
"dataSchema": {
"type": "object",
"properties": {
"state": {
"type": "object",
"format": "lookup"
},
"city": {
"type": "object",
"format": "lookup"
}
}
},
"conditionalValues": [
{
"property": "city",
"query": {
"city.stateId": {
"$eq": "{{state.value}}"
}
}
}
],
"lookupQueries": {
"city": {
"stateId": {
"$eq": "{{state.value}}"
}
}
}
}
}
conditionalValues
property ensures that the "city" field is automatically reset any time the selected "state" field does not correspond to the "stateId" of the selected value for "city"lookupQueries
properties ensures that only options having "stateId" equals to the selected value for "state" are fetched for field "city"
For instance, a valid configuration could be:
{
"state": {
"value": "italy",
"label": "Italy"
},
"city": {
"value": "milan",
"stateId": "italy",
"label": "Milan"
}
}
editing the "state" field triggers the "city" field to be reset. For instance:
{
"state": {
"value": "france",
"label": "France"
},
"city": {}
}
since state.value
no longer equals city.stateId
, the "city" field is reset, due to the confition expressed in conditionalValues
.
At this point, due to the specified lookupQueries
property, HTTP calls to fetch options for the "city" field are performed to /orders/lookup/city
with the following query paramters:
{
"stateId": {
"$eq": "france"
}
}
which might return options like:
[
{
"value": "paris",
"label": "Paris",
"stateId": "france"
},
{
"value": "lione",
"label": "Lione",
"stateId": "france"
}
]
limiting therefore the available options to be coherent with the specified condition in conditionalValues
.
This example features the Dynamic Form Modal. However, the Dynamic Form Drawer and the Dynamic Form Card could be configured in the same way to obtain the same result.
Notice that field "stateId" should be included in the values returned for the "city" field. This can be achieved through proper configuration of the aggregation pipeline that is used to build the underlying writable view.
Components Dynamic Form Modal, Dynamic Form Drawer, Dynamic Form Card always carry in their internal representation of the form values the whole lookup object, although only the label is displayed.
This is why, in the example, conditionalValues
may reference the "stateId" key in the value of the "city" field.