Creating a Custom Editor with Angular

Charon is a flexible data modeling web application that supports user-defined custom editors for fields and documents. By leveraging Web Components, Charon allows developers to seamlessly integrate reusable UI components that can be packaged and distributed via NPM.

This guide walks you through the process of preparing and packaging a Charon-compatible extension. It assumes proficiency with Angular and modern frontend tooling.

Introduction to Web Components

Web Components are a set of standardized browser APIs that allow developers to create reusable and encapsulated HTML elements. Core technologies include:

  • Custom Elements: Define new HTML tags using JavaScript.

  • Shadow DOM: Encapsulate markup and styles.

  • HTML Templates: Define reusable markup structures.

Web Components are framework-agnostic, making them ideal for embedding in applications like Charon.

Charon loads user-defined Web Components dynamically at runtime. Each component is registered via a known selector and associated with supported data types and usage contexts (e.g., form property, grid column).

Step-by-Step: Building a Color Picker Editor

This guide uses a custom color picker field editor as an example. You can download and try the example code referenced in this article.

1. Install the Latest Angular CLI

npm uninstall -g @angular/cli
npm install -g @angular/cli@latest

2. Create a New Angular Project

ng new charon-color-picker --standalone false --ssr false --style sass

Note

Ensure SSR is disabled and SCSS is used for styling.

3. Install Required Dependencies

Install Angular Elements for Web Component support, the Web Components polyfill (for broader compatibility), and the Charon extension types package.

npm install @angular/elements --save
npm install @webcomponents/custom-elements --save
npm install charon-extension --save

4. Write and Export Your Web Component

Follow the official Angular guide to export your component as a custom element:

Key points when writing your component:

  • Implement the CharonPropertyEditorElement interface in your Angular component to accept input properties from the main application.

  • Ensure you correctly subscribe and unsubscribe when valueControl or documentControl input values change, to avoid memory leaks.

  • Export your component with a unique tag name (e.g., ext-color-picker-editor) that is not the same as the Angular component’s selector.

5. Modify angular.json for Packaging

Update the angular.json file:

  • Set the build output path:

    "outputPath": "dist"
    
  • Disable output hashing:

    "outputHashing": "none"
    
  • Change the project type to library:

    "projectType": "library"
    
  • Optionally disable production optimizations during development:

    "configurations": {
      "production": {
        "optimizations": false
      }
    }
    

6. Update package.json for Packaging

Ensure your package.json includes the following:

  • A non-default version number (e.g., 1.0.0).

  • A main field pointing to your generated JS bundle (e.g., main.js).

  • A build script for bundling and packaging:

    "scripts": {
      "build": "ng build && copy package.json dist\\browser\\package.json && cd dist\\browser && npm pack"
    }
    
  • Include your stylesheet(s) in the files array:

    "files": ["styles.css"]
    
  • Declare the Charon extension metadata using the config.customEditors section:

    "config": {
      "customEditors": [
        {
          "id": "ext-color-picker",
          "selector": "ext-color-picker-editor",
          "name": "Color Picker",
          "type": ["Property", "Grid"],
          "dataTypes": ["Text", "Integer"]
        }
      ]
    }
    
  • Add the Charon extension schema reference:

    "$schema": "https://raw.githubusercontent.com/gamedevware/charon-extensions/refs/heads/main/package.json.schema.json"
    
  • Remove the "private": true flag before publishing.

  • Fill in other metadata: author, description, license, etc.

7. Enable Standalone/Zoneless Mode (Performance)

Ensure your component runs independently of Angular’s zone.js. This improves performance and prevents interference between extensions. Refer to Angular documentation for zoneless application setup.

Debugging & Local Testing

Test Locally in Charon

Place the generated .tgz file in:

%PROGRAMDATA%\Charon\extensions\
C:\ProgramData\Charon\extensions\

This allows Charon to detect and load the extension during development, bypassing the NPM publication process.

Project Settings Extensions

Disable Optimizations for Browser Debugging

During debugging, set:

"optimizations": false

in the production build configuration to simplify source maps and runtime behavior.

Versioning

Always increment the version field in package.json between builds to ensure Charon detects updates.

Publishing

Once your component is built, tested, and versioned, you can publish it to NPM and reference it in Charon’s Project Settings Extensions tab. Your custom editor will then be available in the schema designer for relevant property types.

Schema Designer with Custom Editor