Skip to content

component_select

Overview

{
    "could_be_translatable" : false,
    "is_literal"            : false,
    "is_related"            : true,
    "is_media"              : false,
    "modes"                 : ["edit","list","tm","search"],
    "default_tools" : [
        "tool_propagate_component_data",
        "tool_time_machine"
    ],
    "render_views" :[
        {
            "view" : "default | line",
            "mode" : "edit"
        },
        {
            "view" : "print",
            "mode" : "edit"
        },
        {
            "view" : "default | mini | text",
            "mode" : "list | tm"
        }
    ],
    "data"        : "array of locators",
    "sample_data" : [{
        "id"                  : 1,
        "type"                : "dd151",
        "section_tipo"        : "dd64",
        "section_id"          : 1,
        "from_component_tipo" : "test91"
    }],
    "value"        : "array of string",
    "sample_value" : ["Yes"]
}

Typology

component_select is a related component. It does not own a literal value: it stores an array of locators pointing at a target section and resolves the displayed value from that target. Its descriptor (src/core/components/component_select/descriptor.ts) is intentionally thin — almost all behaviour comes from the shared relation engines it links out to.

About default_tools

The toolbar is assembled from the model + ontology; the component class does not hardcode it. The model sample (src/core/components/component_select/samples/context.json) ships tool_propagate_component_data and tool_time_machine. As a non-translatable component, component_select does not receive tool_lang / tool_lang_multi. Tools are read-only context. For language selection that needs translatable behaviour, use the sibling component_select_lang.

TS server implementation

The descriptor src/core/components/component_select/descriptor.ts registers resolveData: 'select_family' (src/core/relations/models/select_family.ts), shared with component_select_lang, component_radio_button, component_check_box, component_publication and component_relation_model. In list/edit/search modes the resolver builds the option datalist and the label strings via src/core/relations/datalist.ts (getDatalist / getRelationListValue, including a faithful strnatcmp re-implementation); every other mode falls through to the shared portal engine (src/core/relations/models/portal.ts). See the dedalo-relations-ts skill.

Definition

component_select is the single-choice dropdown of Dédalo. It renders an HTML <select> whose options are the records of a target section, and stores the user's choice as a single locator relation. Picking an option creates a one-to-one / many-to-one link from the current record to one record in the target section; choosing the empty option removes the relation.

Why it exists. Many catalogue fields are a controlled single choice drawn from a closed or small list: a status, a yes/no flag, a category, a type, a single responsible entity. A relation (rather than a literal string) keeps the chosen value normalised — it points at a real record in a controlled-vocabulary section, so the label resolves consistently, can be renamed in one place, and is queryable from both sides. component_select is the compact UI for that when only one value is allowed and the option set is short enough to fit a dropdown.

When to use it.

  • A single controlled value from a small target list: Conservation status, Object category, Publication state, Yes/No flag, Currency, Material (when single-valued).
  • Choosing one parent / owner / responsible record in a simple relationship.
  • Any place a component_radio_button would work but a dropdown is preferred for space (radio buttons show all options inline; select collapses them into one control).

When not to use it.

  • Multiple values from the same target section -> use component_check_box (multi-select list) or component_portal (rich, paginated, ordered relation list).
  • A large target list where the user must type to find a record -> use component_portal with source.mode: autocomplete (autocomplete service), not a dropdown of thousands of options.
  • A literal string the cataloguer types directly (a title, a note) -> use component_input_text.
  • Tagging the language of sibling content -> use component_select_lang, the language-aware specialisation.

Data model

Data: array of locators. A component_select is single-valued, so the array holds at most one locator.

Value: array of strings, or null. The string is the resolved label of the target record, not a stored value.

Storage shape. A component never writes to the database directly; it reads and saves through its section. A component_select does not keep a private value column — its chosen locator lives in the section-wide relations container, and the component slices out its own locator by matching from_component_tipo (its own tipo). The canonical locator shape is {type, section_tipo, section_id, from_component_tipo} plus the per-item id:

[
    {
        "id"                  : 1,
        "type"                : "dd151",
        "section_tipo"        : "dd64",
        "section_id"          : 1,
        "from_component_tipo" : "test91"
    }
]
  • type is the relation-type tipo. It defaults to DEDALO_RELATION_TYPE_LINK = "dd151" (the generic link type), and can be overridden from properties.config_relation.relation_type.
  • section_tipo / section_id point at the chosen record in the target section.
  • from_component_tipo is forced to this component's own tipo by the relations engine on save (it clones the incoming locator first to protect observers, rejects auto-references and malformed locators, and de-dupes by comparing ['section_tipo','section_id','type','from_component_tipo']compareLocators(), src/core/concepts/locator.ts).
  • id is the per-item counter id used to pair the value with a component_dataframe row when one is attached.

Datum vs. API entries

The transmitted unit is a {context, data} datum (the JSON-API contract). In the API payload the stored locators are surfaced under data.entries, and the selectable options under data.datalist (see src/core/components/component_select/samples/api_data.json). context carries the description (tipo, model, mode, lang, label, properties, permissions, tools, view, request_config, target_sections) and never the values. See the dedalo-context-data-layers and dedalo-datalist-resolution skills for the full layering rules.

The displayed value (["Yes"] in the sample) is resolved from the target section/component, not stored locally. getRelationListValue() (src/core/relations/datalist.ts) walks the resolved option datalist and returns the labels of the options whose locator matches the stored data (compared by section_id + section_tipo).

Ontology instantiation

A component_select is created as an ontology node whose model is component_select. Its parent is the section (or grouper) it belongs to, and its section_tipo wires it into that section. The node declares its label through the standard lg-* term; because it is a related component it is non-translatable (lang resolves to lg-nolan).

Node definition (shape):

{
    "tipo"         : "test91",
    "model"        : "component_select",
    "parent"       : "test3",
    "section_tipo" : "test3",
    "lg-eng"       : "Status",
    "lg-spa"       : "Estado",
    "properties"   : { }
}

The decisive part for a related component is the request config (RQO) inside properties. It declares the target section(s) in sqo.section_tipo and how each option label is resolved in show.ddo_map. Realistic properties block for a single-choice Status select pointing at a controlled-vocabulary section dd64, whose label is the dd62 text column:

{
    "config_relation" : {
        "relation_type" : "dd151"
    },
    "source" : {
        "request_config" : [
            {
                "api_engine" : "dedalo",
                "type"       : "main",
                "sqo" : {
                    "section_tipo" : ["dd64"]
                },
                "show" : {
                    "ddo_map" : [
                        {
                            "tipo"         : "dd62",
                            "model"        : "component_input_text",
                            "section_tipo" : "dd64",
                            "parent"       : "test91",
                            "mode"         : "list",
                            "label"        : "Value"
                        }
                    ],
                    "sqo_config" : { "limit" : 30 }
                }
            }
        ]
    },
    "css" : {
        ".wrapper_component": { "grid-column": "span 4" }
    }
}

When instantiated, the structure context resolves the target sections from the parsed request_config (TS: buildRequestConfigForElement + extractSqoSectionTipos, src/core/relations/request_config/build.ts and request_config/v6.ts) and attaches each as context.target_sections, and — in edit mode — populates data.datalist (TS: getDatalist, src/core/relations/datalist.ts). On save, the section is the single writer: the chosen locator is persisted into the section relations container, not a private data column.

Properties & options

All properties are optional and live in the ontology node properties JSON. component_select adds no component-specific scalar flags of its own; it consumes the shared related-component properties. Verified names:

source / request_config

  • Values: an object with request_config (an array of RQO blocks). The RQO declares sqo.section_tipo (the target section list) and show.ddo_map (which target component resolves each option label and how — value_with_parents, fields_separator, etc.).
  • Effect: this is what makes the dropdown work. getDatalist() (src/core/relations/datalist.ts) runs the RQO against the target section(s) to build data.datalist (the <option> set); target_sections is derived from sqo.section_tipo. A select with no resolvable request_config logs an error and produces an empty option list. See the dedalo-datalist-resolution and dedalo-request-config skills.

config_relation

  • Values: an object {relation_type, relation_type_rel}.
  • Effect: overrides the relation tipo written into each locator. relation_type defaults to the descriptor's defaultRelationType (dd151) for component_select; set it to use a different relation type. relation_type_rel records directionality (uni/bi/multidirectional); component_select declares no default directionality, so the link is unidirectional, stored only on the originating side.

css

  • Values: an object keyed by CSS selector (e.g. .wrapper_component), each a map of declarations.
  • Effect: style stamped on the rendered wrapper. Commonly used to set the grid span of the field.

has_dataframe

  • Values: true | false (default false).
  • Effect: marks the component as paired with a component_dataframe. When the RQO show.ddo_map contains a component_dataframe entry, the server builds the dataframe subdatum and the default edit view attaches a dataframe control to the selected value (pairing key is the value item id, never the target section_id). Changing the select value fires an explicit delete_dataframe unlink before the new value is saved. See the dedalo-dataframe skill.

Standard context properties

Like every component, component_select also honours the generic ontology context blocks carried into the datum context: properties, request_config (RQO) and view (the render view to use). Observer/observable wiring, when needed, is configured in properties like any other component (see the index page Observers and observables section). Any other custom key seen in production should be verified in the ontology.

Single value enforced in the client

The dropdown structurally allows only one choice. The client also enforces it on the new record path: it first removes any existing locator (a remove save) before creating and linking the new target record, so the select never accumulates more than one relation.

Render views & modes

Views are selected from context.view (default default) and dispatched by the per-mode render files (render_edit_component_select.js, render_list_component_select.js, render_search_component_select.js). Verified from the source:

View edit list / tm search Notes
default yes yes (via search render) edit: <select> with options from data.datalist, plus optional new / go to target / tool buttons; selecting attaches the dataframe when configured. list: read-only joined value in the wrapper, click activates edit-in-list (modal).
line yes Compact inline <select> without label; reuses the same content-data builder, adds a button exit edit.
print yes Reuses the default edit view but forces permissions = 1 (read-only content_value) and is tagged for print context.
mini yes Minimal wrapper used by service autocomplete / datalists.
text yes / tm Plain <span> with the joined value (entries joined by context.fields_separator), no chrome.

The search render builds a filter input per entry: a q_operator text input plus the same <select> (with an empty option prepended), publishing change_search_element as the user edits. It produces an SQO filter over the related target; saves are blocked in search mode.

Modes:

  • edit — read/write a real record; populates datalist, supports choosing/removing the single value, creating a new target record (add), opening the target record/list, and attaching a dataframe. The +1 selection from the empty option clears the relation (action: remove); any other choice is an action: update.
  • list / tm — read-only listing; tm (Time Machine) reuses the list render. The stored locator is resolved to its target label.
  • search — builds the SQO filter input; saves are refused.

DOM (edit / default): wrapper_component component_select <tipo> <mode> view_default -> label, buttons_container, content_data -> content_value -> select.select (one <option> per datalist item, value = JSON.stringify(locator)).

Import / export model

Import. component_select goes through the shared related-component import engine (conformImportData(), src/core/tools/import_data.ts). Two formats are accepted (see importing data):

  • JSON locator array (default round-trip format) — a one-element array since the component is single-valued:
[{"type":"dd151","section_tipo":"dd64","section_id":1,"from_component_tipo":"test91"}]
  • Plain section_id when the target section is unambiguous (a single target in the RQO, or disambiguated by the CSV column header tipo_targettipo, e.g. test91_dd64). The importer builds the full locator from that id:
1

from_component_tipo is forced to this component's own tipo, type is injected from the resolved relation type, the section_id is validated, and invalid / multi-target-without-clear-target rows are logged and ignored. An empty cell is valid and clears the existing relation.

Export. The shared relation export path iterates the stored locator and, per the ddo_map, resolves the target component against the locator's section_id / section_tipo to produce the displayed label / sub-columns; the indexation grid resolves the same way. See exporting data and the dedalo-export skill.

Notes

  • Observers / observables. No component-specific subscriptions are hardcoded. Observer/observable wiring is configured in the ontology properties like any other component (see the index page Observers and observables section).
  • Default tools. A standard instance exposes tool_propagate_component_data and tool_time_machine in context.tools (model sample). Being non-translatable, it does not receive tool_lang / tool_lang_multi.
  • Sortable. resolveSortable() (src/core/resolve/structure_context.ts) defaults every model to sortable and component_select's descriptor does not opt out, so a component_select column can be used to sort a list. (Note: when used as a column inside a component_portal, portal column sort excludes select-type columns — that is the portal's policy for its own sub-columns, separate from this component's own sortability.)
  • Shared relation behaviour. The chosen value lives only in the section relations bag; the component filters by from_component_tipo. Locator normalisation and validation, adding/removing a locator (with the dataframe cascade), grid/export/diffusion resolution and search all come from the shared relations engine (src/core/relations/), not from anything this model declares itself.
  • Related components: component_select_lang, component_radio_button, component_check_box, component_portal, component_relation_model, component_dataframe, component_input_text.