Skip to content

Inline Creation in Views

Martynas Jusevičius edited this page Jan 20, 2026 · 4 revisions

Overview

This document proposes a feature for enabling users to create related items inline within resource views, eliminating the need to navigate away from context.

Problem Statement

Currently, when viewing a resource with related items (e.g., a SKOS Concept with "Narrower Concepts" view), users must:

  1. Leave the current page
  2. Navigate to a container to create a new item
  3. Manually establish the relationship back to the parent resource
  4. Return to the original resource

This breaks user context and creates a poor user experience.

Solution Overview

Enable inline creation directly within ldh:View resources that are attached to properties via ldh:view or ldh:inverseView. When a view displays related items, users can create new items directly in that view with automatic relationship establishment.

Architecture

Property-Driven Views

LinkedDataHub uses a property-driven view architecture where:

  • ldh:view: Attaches views to properties for forward relationships ($about property ?value)
  • ldh:inverseView: Attaches views to properties for inverse relationships (?value property $about)
  • Views are ldh:View resources containing SPARQL queries that render related data

Example from SKOS package:

skos:narrower ldh:view :NarrowerConcepts .

:NarrowerConcepts a ldh:View ;
    dct:title "Narrower concepts" ;
    spin:query :SelectNarrowerConcepts .

:SelectNarrowerConcepts a sp:Select ;
    sp:text """
    SELECT DISTINCT ?narrower
    WHERE { GRAPH ?graph { $about skos:narrower ?narrower } }
    ORDER BY ?narrower
    """ .

Inline Creation Metadata

To enable inline creation within views, add the following properties to ldh:View resources:

Required Properties

  • ldh:container: The container URI where new items will be created via HTTP PUT

Optional Properties

  • ldh:showWhenEmpty: Controls whether the view displays when the query returns no results (defaults to true)

Automatic Inference

The property-driven architecture enables automatic inference of:

Property - Implicit from the view's attachment point:

  • The property that has ldh:view or ldh:inverseView pointing to this view
  • For ldh:view: Forward relationship (parent → child)
  • For ldh:inverseView: Inverse relationship (child → parent)

Type - Inferred from the property's ontology definition:

  • Forward relationships (ldh:view): Use the property's rdfs:range
  • Inverse relationships (ldh:inverseView): Use the property's rdfs:domain

Example:

# skos:narrower has rdfs:range skos:Concept
skos:narrower ldh:view :NarrowerConcepts .

# Property is implicit: skos:narrower (from attachment)
# Type is inferred: skos:Concept (from rdfs:range)
# Direction: forward (ldh:view)
# skos:inScheme has rdfs:domain skos:Concept
skos:inScheme ldh:inverseView :ConceptsInScheme .

# Property is implicit: skos:inScheme (from attachment)
# Type is inferred: skos:Concept (from rdfs:domain)
# Direction: inverse (ldh:inverseView)

Implementation Strategy

1. Automatic Inference (Primary Approach)

For ~80% of common cases, everything is automatically inferred:

  1. Infer property: Query ontology for ?property ldh:view <thisView> or ?property ldh:inverseView <thisView>
  2. Infer type:
    • For ldh:view: Query ?property rdfs:range ?type
    • For ldh:inverseView: Query ?property rdfs:domain ?type
  3. Use configured container: From ldh:container on the view

Example (no explicit metadata needed):

skos:narrower ldh:view :NarrowerConcepts .

:NarrowerConcepts a ldh:View ;
    dct:title "Narrower concepts" ;
    spin:query :SelectNarrowerConcepts ;
    ldh:container <concepts/> .

# Everything else is automatic!

2. Explicit Container (Always Required)

The only metadata that MUST be specified is the container:

:NarrowerConcepts a ldh:View ;
    dct:title "Narrower concepts" ;
    spin:query :SelectNarrowerConcepts ;
    ldh:container <concepts/> .  # Required: where to create items

3. Edge Cases

For complex scenarios where inference might fail:

  • Property paths: skos:broader+
  • UNION queries with multiple properties
  • Missing rdfs:range or rdfs:domain definitions
  • Transitive properties

In these cases, inline creation may need to be disabled or handled with custom logic.

User Flow

Forward Relationship Example (ldh:view)

Viewing a skos:Concept resource:

  1. User sees "Narrower Concepts" view displaying existing narrower concepts
  2. View includes an [Add New] button
  3. Clicking opens a modal form for creating a new concept
  4. System infers property from attachment: skos:narrower
  5. System infers type from rdfs:range of skos:narrowerskos:Concept
  6. User enters concept details (slug, label, definition, etc.)
  7. System issues HTTP PUT to ldh:container to create the new concept
  8. System automatically adds parent skos:narrower newConcept triple
  9. View refreshes to show the new concept

Inverse Relationship Example (ldh:inverseView)

Viewing a skos:ConceptScheme resource:

  1. User sees "Concepts in Scheme" view displaying concepts that reference this scheme
  2. View includes an [Add New] button
  3. Clicking opens a modal form for creating a new concept
  4. System infers property from attachment: skos:inScheme
  5. System infers type from rdfs:domain of skos:inSchemeskos:Concept
  6. User enters concept details
  7. System issues HTTP PUT to ldh:container to create the new concept
  8. System automatically adds newConcept skos:inScheme scheme triple
  9. View refreshes to show the new concept

Enterprise Applications

This feature enables building functional enterprise CRUD applications declaratively:

  • Schema.org Vocabularies: Use standard vocabularies (Organization, Person, Event, Product, etc.)
  • XSLT Components: Build interactive UI patterns (tabs, sortable tables, bulk operations)
  • Property-Driven Views: Attach views to vocabulary properties for automatic rendering
  • Inline Creation: Enable contextual data entry without navigation

Example: Building a CRM using Schema.org:

schema:employee ldh:view :EmployeeList .

:EmployeeList a ldh:View ;
    dct:title "Employees" ;
    spin:query :SelectEmployees ;
    ldh:container <employees/> .

# Property: inferred from attachment (schema:employee)
# Type: inferred from rdfs:range of schema:employee
# Direction: forward relationship (ldh:view)

Implementation Checklist

Vocabulary

  • Add ldh:container to ldh.ttl
  • Add ldh:showWhenEmpty to ldh.ttl

XSLT (Client-Side)

  • SPARQL SELECT on ontology: Find property from view attachment (SELECT ?property WHERE { ?property ldh:view <thisView> } or ldh:inverseView)
  • SPARQL SELECT on ontology: Determine direction (check if result came from ldh:view or ldh:inverseView query)
  • SPARQL SELECT on ontology: Infer type via rdfs:range (forward) or rdfs:domain (inverse)
  • Render [Add New] button in view templates (only when ldh:container is present)
  • Show modal form with inferred type (standard LinkedDataHub form, but modal)
  • On form save: Issue PUT to ldh:container to create new instance (standard LinkedDataHub behavior)
  • After PUT succeeds: Issue PATCH to add linking triple:
    • Forward (ldh:view): PATCH parent document with INSERT DATA { <parent> <property> <newInstance> }
    • Inverse (ldh:inverseView): PATCH new document with INSERT DATA { <newInstance> <property> <parent> }

Testing

  • HTTP tests for inline creation with forward relationships
  • HTTP tests for inline creation with inverse relationships
  • UI tests for modal form behavior
  • Edge cases: missing domain/range, inference failures
  • Property inheritance via rdfs:subPropertyOf

Related Documentation

Version

This feature proposal is for LinkedDataHub 5.2.1+, which introduced the property-driven view architecture with ldh:view and ldh:inverseView.

Clone this wiki locally