create-entity-viewmodel
Create a new entity ViewModel with property ViewModels following {{sharedLib}} MVVM patterns. Use when adding new data models, creating entity wrappers, or scaffolding ViewModels for entities. Handles property VM creation, label converters, base class selection, and test generation.
安装与使用
请根据来源仓库和你的 AI 工具说明安装此技能。先阅读技能文件和依赖要求,再添加到工作流。
查看来源 ↗使用指南技能说明
Create Entity ViewModel
This skill scaffolds a complete entity ViewModel following {{sharedLib}} framework patterns.
When to Use
- Creating a new entity ViewModel for a data model
- Wrapping an existing model with UI logic
- Adding property ViewModels for entity properties
- Setting up label converters for enum types
Prerequisites
- Data model must exist in
/model/*.model/src/and be generated - Run
npm run generate-modelif model was just created - Entity should be defined with proper property types (ValueProperty, CommandedProperty, etc.)
Process
Step 1: Understand the Data Model
Read the source model to understand:
- Property types (ValueProperty, CommandedProperty, RangedCommandedProperty)
- Enum types that need label converters
- Geographic properties (lat/lon/alt)
- Parent class (Entity, GeoEntity, Platform, etc.)
Reference: ENTITY_ARCHITECTURE.md
Step 2: Choose the Right Base Class
Determine appropriate base class:
- EntityViewModel - Standard entities (settings, configs)
- GeoEntityBaseVM - Entities with location data (platforms, vehicles)
- GeoPointBaseVM - Simple geographic points (waypoints, markers)
- Custom abstract base - Multiple related entities share functionality
Reference: ENTITY_ARCHITECTURE.md - Best Practices
Step 3: Create Property ViewModels
For each property on the model, create appropriate property VM:
Property Type Mapping:
-
ValueProperty<string>→StringViewModel -
CommandedProperty<string>→CommandedStringViewModel -
ValueProperty<number>→NumberViewModel -
RangedCommandedProperty<number>→RangedCommandedNumberViewModel -
CommandedProperty<boolean>→CommandedBooleanViewModel -
CommandedProperty<EnumType>→CommandedEnumViewModel<EnumType> -
ValueProperty<string[]>→ArrayViewModel<string> -
CommandedProperty<string[]>→CommandedArrayViewModel<string>
CRITICAL Patterns:
- Use
CommandedArrayViewModel, NOTArrayViewModelfor commanded arrays - Use
RangedCommandedNumberViewModelfor numbers with min/max, NOTCommandedNumberViewModel - Always add type hints for labelConverter:
(value: number | null | undefined) => string - Return
'---'for null/undefined values in labelConverter
@computed Decorator Usage:
Use @computed when getter:
- Includes configuration (labelConverter, defaultValue, etc.) - prevents re-running configure
- Derives/computes values from observables
- Filters or transforms data
// ✅ With configuration - use @computed
@computed
get modeVM(): ICommandedVM<ModeType, IEnumFormatOptions<ModeType>> {
const vm = this.createPropertyVM('mode', CommandedEnumViewModel<ModeType>);
vm.configure({
labelConverter: ModeTypeLabel,
defaultValue: ModeType.DEFAULT
});
return vm;
}
// ✅ Simple forwarding - @computed optional (micro-optimization)
get nameVM(): IPropertyVM<string, IStringFormatOptions> {
return this.createPropertyVM('name', CommandedStringViewModel);
}
// ✅ Derived values - @computed required
@computed
get activeItems(): EntityViewModel[] {
return this.items.filter(item => item.isActive);
}
Reference: ENTITY_ARCHITECTURE.md - Property ViewModel Patterns
Step 4: Create Label Converters for Enums
For each enum type, create a label converter in adapters/types.ts:
export const YourEnumTypeLabel: Record<YourEnumType, string> = {
[YourEnumType.VALUE1]: 'Display Label 1',
[YourEnumType.VALUE2]: 'Display Label 2',
};
Reference: ENTITY_ARCHITECTURE.md - Label Converter Creation
Step 5: Implement Required Methods
All entity ViewModels must implement:
-
getEntityClassName()- ReturnsModelClass.class -
getEntityCtr()- Returns the model constructor
Reference: COOKBOOK_PATTERNS_ENHANCED.md - Complete Entity ViewModel
Standard Import Pattern:
// Framework interfaces and types
import { IEntityConstructor, IFrameworkServices, IPropertyVM, ICommandedVM, IEnumFormatOptions, IStringFormatOptions, INumberFormatOptions } from '@{{company}}/framework-api';
// Entity ViewModel base and property VMs (from {{sharedLib}}-core)
import { EntityViewModel, CommandedStringViewModel, CommandedEnumViewModel, RangedCommandedNumberViewModel, CommandedArrayViewModel } from '@{{company}}/{{sharedLib}}-core';
// MobX decorators
import { computed, makeObservable } from 'mobx';
// Model and types
import { MyEntity } from '@{{company}}/your-model-package';
import { MyEnumType } from '@{{company}}/your-model-package';
// Label converters (from adapters)
import { MyEnumTypeLabel } from '../adapters/types';
Step 6: Add MobX Support
CRITICAL: Call makeObservable(this) in constructor!
constructor(services: IFrameworkServices) {
super(services);
makeObservable(this); // REQUIRED for reactivity
}
Reference: MOBX_ESSENTIALS.md - Constructor Pattern
Step 7: Update Barrel Exports
Add to {lib}.core/src/index.ts:
export * from './lib/viewModels/yourEntityViewModel';
Add label converters to {lib}.core/src/lib/adapters/index.ts:
export * from './types';
Step 8: Create Tests
Generate unit tests following patterns:
- Mock IFrameworkServices
- Test property VM creation
- Test getEntityClassName/getEntityCtr
- Test label converters
Reference: TESTING_GUIDE.md
Common Pitfalls to Avoid
Reference: COMMON_PITFALLS.md
- ❌ Don't use
BaseEntityViewModel- UseEntityViewModelfrom {{sharedLib}}-core - ❌ Don't use
ArrayViewModelfor commanded arrays - UseCommandedArrayViewModel - ❌ Don't forget
makeObservable(this)in constructor - ❌ Don't use
CommandedNumberViewModelfor constrained numbers - UseRangedCommandedNumberViewModel - ❌ Don't hardcode labels - Create label converters in adapters
- ❌ Don't forget type hints on labelConverter functions
- ❌ Don't return 'N/A' for null - Use
'---' - ❌ Don't forget
@computedon property VMs with configuration or derived values
Complete Template
Reference: COOKBOOK_PATTERNS_ENHANCED.md - Complete Entity ViewModel
File Locations
- Entity ViewModels:
{lib}.core/src/lib/viewModels/ - Label Converters:
{lib}.core/src/lib/adapters/types.ts - Tests:
{lib}.core/src/lib/viewModels/__tests__/
Verification Steps
After creation:
- Run
./tools/build-helpers/count-client-errors.sh- Should be 0 - Run
npm test- New tests should pass - Verify exports in index.ts
- Check label converters work in UI components
Ask User If Unclear
- Which library to create the VM in ({{projectName}}.core, alpha.core, etc.)
- Whether this is a geographic entity (needs GeoEntityBaseVM)
- Default values for enum properties
- Whether to create abstract base class (if multiple similar entities)
使用示例
查看来源仓库中的使用示例与配置说明。
查看来源 ↗来源历史
- 收录时间
- 2026-01-20
- 索引更新时间
- 2026-01-26
- Branch
- main
收录与同步日期属于本站记录。源码修改历史请查看来源仓库。
GitHub ↗chat Comments (0)
Sign in to join the discussion and leave a comment.
No comments yet. Be the first to share your thoughts!