Angular Explorer Packages
These packages comprise the MJExplorer application, MemberJunction’s primary Angular-based UI for browsing, editing, and managing data. They are published individually under the @memberjunction npm scope and consumed together by the MJExplorer host application.
Guides
Section titled “Guides”- Navigation & Routing Guide — How navigation, URL sync, back/forward, and query param sub-navigation work in MJ Explorer
- Dashboard Best Practices — Architecture patterns for building dashboards
Packages
Section titled “Packages”Core / Shell
Section titled “Core / Shell”Foundational packages that provide the application shell, routing, authentication, shared utilities, and module bundling.
| Package | npm | Description |
|---|---|---|
| explorer-app | @memberjunction/ng-explorer-app | Complete branded entry point for Explorer-style applications |
| explorer-core | @memberjunction/ng-explorer-core | Core Explorer framework: application shell, routing, resource containers, and navigation |
| explorer-modules | @memberjunction/ng-explorer-modules | Consolidated Explorer NgModule bundle that re-exports all Explorer feature modules |
| base-application | @memberjunction/ng-base-application | BaseApplication class system for app-centric navigation |
| auth-services | @memberjunction/ng-auth-services | Authentication services with Auth0, MSAL, and Okta provider support |
| shared | @memberjunction/ng-shared | Shared Explorer utilities, base components, services, and events used across Explorer packages |
| workspace-initializer | @memberjunction/ng-workspace-initializer | Workspace initialization service and components for bootstrapping the Explorer environment |
Forms & Entity Editing
Section titled “Forms & Entity Editing”Components for rendering, editing, and managing entity records through metadata-driven forms.
| Package | npm | Description |
|---|---|---|
| base-forms | @memberjunction/ng-base-forms | Base form components, field rendering, and validation framework |
| core-entity-forms | @memberjunction/ng-core-entity-forms | Auto-generated and custom entity forms with dynamic form loading and registration |
| entity-form-dialog | @memberjunction/ng-entity-form-dialog | Modal dialog for displaying and editing any entity record |
Data Grids & Lists
Section titled “Data Grids & Lists”Grid and list components for browsing and managing collections of entity records.
| Package | npm | Description |
|---|---|---|
| list-detail-grid | @memberjunction/ng-list-detail-grid | Master-detail grid for displaying dynamic and saved list details |
| simple-record-list | @memberjunction/ng-simple-record-list | Lightweight component for displaying, editing, creating, and deleting records in any entity |
Dashboards
Section titled “Dashboards”Dashboard components for administrative and analytical views.
| Package | npm | Description |
|---|---|---|
| dashboards | @memberjunction/ng-dashboards | Dashboard components including AI model management, Entity Admin ERD, and Actions configuration |
Utility & Navigation
Section titled “Utility & Navigation”Supporting components for linking, permissions, settings, and change tracking.
| Package | npm | Description |
|---|---|---|
| link-directives | @memberjunction/ng-link-directives | Directives for turning elements into email, web, or record links |
| entity-permissions | @memberjunction/ng-entity-permissions | Components for displaying and editing entity-level permissions |
| explorer-settings | @memberjunction/ng-explorer-settings | Reusable components for the Explorer settings section |
| record-changes | @memberjunction/ng-record-changes | Change-tracking dialog with diff visualization for individual records |
Dynamic Loading Architecture
Section titled “Dynamic Loading Architecture”MJExplorer uses a fully metadata-driven architecture where routes, navigation, and component loading are resolved at runtime rather than statically declared. This enables unlimited custom dashboards and resources without changing core code.
How Routing Works
Section titled “How Routing Works”Routes are not statically mapped to components. Instead, a ResourceResolver intercepts URL patterns and converts them into tab requests:
- URL like
/app/Admin/AI%20Modelsis activated ResourceResolverreads the Application entity’sDefaultNavItemsJSON from the database- Finds the matching nav item by label, which specifies a
DriverClassstring (e.g."AIModelsResource") andResourceType(e.g."Custom") - Calls
TabService.OpenTab()with that configuration ResourceContainerComponentrenders the tab content (see next section)
This means Angular has no compile-time knowledge of which components map to which routes. Everything is resolved through metadata and the ClassFactory.
How Components Are Discovered at Runtime
Section titled “How Components Are Discovered at Runtime”Every dashboard and resource component registers itself with MJGlobal’s ClassFactory via the @RegisterClass decorator:
@RegisterClass(BaseResourceComponent, 'AIModelsResource')export class ModelManagementComponent extends BaseResourceComponent { }When a tab becomes visible, ResourceContainerComponent does:
ClassFactory.GetRegistrationAsync(BaseResourceComponent, 'AIModelsResource')— async lookup that triggers lazy loading if neededviewContainerRef.createComponent(registeredClass)— Angular’s dynamic component API instantiates it- Wires up
Datainput and event callbacks
Universal Lazy Loading via ClassFactory
Section titled “Universal Lazy Loading via ClassFactory”Not all components are in the initial bundle. Lazy loading is handled universally by ClassFactory itself — no consumer-specific retry logic needed:
ClassFactory.GetRegistrationAsync()tries sync lookup first- If
null, calls registered lazy loaders with('BaseResourceComponent', 'AIModelsResource') LazyModuleRegistrybuilds the compound key'BaseResourceComponent::AIModelsResource'and looks it up inLAZY_FEATURE_CONFIG- The config maps to a dynamic import:
import('@memberjunction/ng-dashboards/ai-dashboards.module') - The chunk loads,
@RegisterClassdecorators execute — ClassFactory now has the class - Retry succeeds, component renders normally
This works for ALL base classes (BaseResourceComponent, BaseDashboard, BaseApplication, etc.), not just resource components. Any consumer using CreateInstanceAsync or GetRegistrationAsync gets lazy loading automatically.
See guides/LAZY_LOADING_GUIDE.md for the complete guide.
Tree-Shaking Prevention via Manifests
Section titled “Tree-Shaking Prevention via Manifests”Modern bundlers (ESBuild, Vite) cannot detect that ClassFactory.CreateInstance('AIModelsResource') needs a specific class — there’s no static import path. Without intervention, the bundler tree-shakes these classes as dead code.
MemberJunction solves this with class registration manifests generated by mj codegen manifest. The generator walks the dependency tree, finds every @RegisterClass-decorated class via TypeScript AST parsing, and emits a file with explicit named imports:
import { ModelManagementComponent } from '@memberjunction/ng-dashboards';import { PromptManagementComponent } from '@memberjunction/ng-dashboards';// ... hundreds more
export const CLASS_REGISTRATIONS = [ ModelManagementComponent, PromptManagementComponent, // ...];The bundler sees named imports referenced in an exported array — it cannot tree-shake them.
Dual-manifest architecture:
- Pre-built manifests ship inside bootstrap packages (
@memberjunction/ng-bootstrap,@memberjunction/ng-bootstrap-lite). Generated at MJ release time, they cover all@memberjunction/*classes. - Supplemental manifests are generated locally at
prestart/prebuildwith--exclude-packages @memberjunctionto capture only user-defined custom classes.
For lazy-loaded modules, ng-bootstrap-lite intentionally excludes dashboard and settings packages. Those classes aren’t in the initial manifest (so they’re not in the initial bundle). They get pulled in via dynamic import() when the user navigates to them.
See /packages/CodeGenLib/CLASS_MANIFEST_GUIDE.md for comprehensive manifest documentation.
Key Files
Section titled “Key Files”| File | Role |
|---|---|
explorer-core/.../app-routing.module.ts | Route definitions and ResourceResolver |
explorer-core/.../resource-container-component.ts | Dynamic component loading with lazy fallback |
explorer-core/.../services/lazy-module-registry.ts | Manages lazy chunk loading and deduplication |
explorer-core/.../services/lazy-feature-config.ts | Maps 60+ resource types to dynamic import functions |
dashboards/package.json (exports field) | Subpath exports enabling ESBuild code splitting |
@memberjunction/ng-bootstrap-lite | Pre-built manifest excluding lazy-loaded packages |