# @memberjunction/angular-elements-demo Demonstrates how to leverage Angular Elements to create reusable web components from MemberJunction Angular components that can be embedded in any web application, regardless of the framework used. ## Overview Angular Elements provides a bridge between Angular's powerful component model and the Web Components standard. By converting Angular components into standard Custom Elements, MemberJunction functionality can be used in non-Angular environments including React, Vue, and plain HTML pages. ```mermaid graph TD A["Angular Components"] -->|"createCustomElement()"| B["Custom Elements
(Web Components)"] B --> C["mj-hello-world"] B --> D["mj-entity-list-demo"] B --> E["mj-entity-detail-demo"] B --> F["mj-listener-demo"] G["Any Web Page"] --> C G --> D G --> E G --> F D -->|"rowClicked event"| E H["MJ GraphQL API"] --> C H --> D H --> E style A fill:#2d6a9f,stroke:#1a4971,color:#fff style B fill:#7c5295,stroke:#563a6b,color:#fff style C fill:#2d8659,stroke:#1a5c3a,color:#fff style D fill:#2d8659,stroke:#1a5c3a,color:#fff style E fill:#2d8659,stroke:#1a5c3a,color:#fff style F fill:#2d8659,stroke:#1a5c3a,color:#fff style G fill:#b8762f,stroke:#8a5722,color:#fff style H fill:#2d6a9f,stroke:#1a4971,color:#fff ``` This approach gives you the best of both worlds -- Angular's powerful development environment and the universal compatibility of Web Components. ## Strategic Value Angular Elements offers several strategic advantages for organizations: ### 1. Cross-Framework Compatibility Modern web development often involves multiple frameworks. Angular Elements allows you to: - Leverage existing Angular components in React, Vue, or even plain JavaScript applications - Create a unified component library that works everywhere - Avoid framework lock-in while still using the tools you prefer ### 2. Incremental Migration Path For applications transitioning between frameworks: - Gradually move from one framework to another while maintaining functionality - Reuse components during migration rather than rewriting everything - Provide a smoother upgrade path with less risk ### 3. Microfrontend Architecture Angular Elements is perfect for microfrontend architectures: - Different teams can work with different frameworks but share components - Core functionality can be encapsulated in framework-agnostic web components - Applications can be composed from independently deployable components ### 4. Design System Implementation For implementing design systems: - Create components once and use them everywhere - Ensure consistent behavior and appearance across applications - Simplify maintenance by centralizing component logic ## Components Included This package exports the following MemberJunction components as web components: ### 1. `` A simple demonstration component that: - Connects to MemberJunction's metadata system - Displays the total count of entities - Emits events with entity information - Shows basic MemberJunction integration **Properties:** None **Events:** `display` - Emits entity list data ### 2. `` Displays a list of MemberJunction entities in a table format: - Loads entity metadata automatically when user is logged in - Handles row selection with visual feedback - Emits events when rows are clicked - Manages Angular change detection for web component usage **Properties:** None **Events:** `rowClicked` - Emits selected EntityInfo object ### 3. `` Shows detailed information about a selected entity: - Accepts an EntityInfo object as input - Displays entity properties in a grid layout - Updates automatically when input changes **Properties:** `entity` (EntityInfo) - The entity to display **Events:** None ### 4. `` Demonstrates event listening capabilities: - Subscribes to MemberJunction global events - Logs event information to console - Shows how components can communicate via event system **Properties:** `displayString` (string) - Text to display **Events:** None ### 5. `` A wrapper component for the MemberJunction user view grid (implementation pending). ## Installation ### Prerequisites - Node.js (LTS version recommended) - npm or yarn - Angular CLI (`npm install -g @angular/cli`) - MemberJunction backend API running (for data functionality) ### Package Installation This package is part of the MemberJunction monorepo. To work with it: 1. Clone the MemberJunction repository 2. Navigate to the root directory 3. Install all dependencies (from the monorepo root): ```bash npm install ``` 4. Navigate to this package: ```bash cd packages/AngularElements/mj-angular-elements-demo ``` ## Building the Web Components ### Development Build ```bash # Build in development mode ng build # or npm run build ``` ### Production Build with Bundling Run the build script to create the bundled web components: ```bash # Make the script executable (first time only) chmod +x build_angular_elements.sh # Run the build script ./build_angular_elements.sh ``` This script: 1. Builds the Angular application with production optimizations 2. Concatenates the resulting JavaScript files (runtime, polyfills, scripts, main) 3. Creates a single bundle (`dist/mj-angular-elements-demo-complete.js`) that can be included in any web page ### Build Output - `dist/mj-angular-elements-demo/`: Standard Angular build output - `dist/mj-angular-elements-demo-complete.js`: Bundled file containing all components ### Available NPM Scripts ```bash npm run build # Build the project npm run watch # Build and watch for changes npm run start # Start development server npm run test # Run unit tests ``` ## Usage Examples ### Basic Usage Include the generated bundle in any HTML page: ```html ``` ### Complete Example with MemberJunction Integration ```html
``` ### Demo Pages This package includes working demo pages: - `demo_mj_hello_angular_elements.html`: Simple hello world component demo - `demo_mj_entity_list_angular_elements.html`: Advanced demo showing entity list and detail components working together with event communication ## API Documentation ### Component Communication Components communicate through standard DOM events and properties: ```javascript // Listen for events from a component const entityList = document.querySelector('mj-entity-list-demo'); entityList.addEventListener('rowClicked', event => { // Access the data passed with the event const entityData = event.detail; // EntityInfo object // Pass data to another component via property const entityDetail = document.querySelector('mj-entity-detail-demo'); entityDetail.entity = entityData; }); // Set properties directly const listener = document.querySelector('mj-listener-demo'); listener.displayString = 'Hello from JavaScript!'; ``` ### TypeScript Support When using these components in a TypeScript project: ```typescript import { EntityInfo } from '@memberjunction/core'; // Type the elements const entityList = document.querySelector('mj-entity-list-demo') as HTMLElement & { addEventListener(type: 'rowClicked', listener: (event: CustomEvent) => void): void; }; const entityDetail = document.querySelector('mj-entity-detail-demo') as HTMLElement & { entity: EntityInfo; }; // Use with full type safety entityList.addEventListener('rowClicked', (event) => { entityDetail.entity = event.detail; // TypeScript knows this is EntityInfo }); ``` ## Implementation Approach ### Understanding Angular Elements Angular Elements works by: 1. Creating a standard Angular component 2. Converting it to a Custom Element using `createCustomElement()` 3. Registering it with the browser using `customElements.define()` When the component is used in a web page: 1. Angular bootstraps a mini-app for each component instance 2. `@Input()` properties become attributes or properties of the custom element 3. `@Output()` events become standard DOM events 4. Change detection works as expected within the component ### Technical Considerations When implementing Angular Elements: 1. **Bundle Size**: Angular Elements includes Angular's core runtime with each component, so bundle size optimization is important. - Consider using `ngx-build-plus` for more efficient bundling - For very large applications, lazy loading chunks may be beneficial 2. **Zone.js**: Angular Elements relies on Zone.js for change detection: - Include Zone.js in your bundle or load it separately - Be aware of potential conflicts with other frameworks using Zone.js 3. **Shadow DOM**: By default, Angular Elements uses Shadow DOM for style encapsulation: - This isolates styles from the rest of the page - You can configure this behavior with the `ViewEncapsulation` setting 4. **Browser Support**: Custom Elements are supported in all modern browsers, but polyfills may be needed for older browsers: - `@webcomponents/custom-elements` provides necessary polyfills - Consider using a polyfill loading strategy for optimal performance ## Developing New Components ### Creating Components for Dual Use You can design your Angular components to work both as regular Angular components and as web components: 1. **Design for standalone use**: Ensure components can function with minimal external dependencies 2. **Use Input/Output for communication**: Rely on `@Input()` and `@Output()` decorators for component interaction 3. **Handle change detection**: When used as web components, Angular's change detection works differently, so manually trigger detection when needed ### Converting to Web Components In your Angular module, convert components to custom elements: ```typescript import { NgModule, Injector } from '@angular/core'; import { createCustomElement } from '@angular/elements'; import { YourComponent } from './your-component'; @NgModule({ declarations: [YourComponent], imports: [...], }) export class AppModule { constructor(injector: Injector) { // Convert Angular component to custom element const element = createCustomElement(YourComponent, {injector}); // Define the custom element customElements.define('your-element', element); } ngDoBootstrap() {} // Required for custom elements } ``` ## Best Practices 1. **Keep dependencies minimal**: Web components work best when they have few external dependencies 2. **Use shadow DOM wisely**: Angular Elements uses shadow DOM by default, which provides style isolation 3. **Handle events properly**: Use standard DOM events for communication between components 4. **Document attributes and events**: Clear documentation helps others use your web components 5. **Consider polyfills**: For older browsers, include web components polyfills 6. **Optimize bundle size**: Use tree-shaking, code splitting, and other techniques to reduce payload size 7. **Test in all target browsers**: Ensure your components work in all browsers you need to support ## Real-World Use Cases ### 1. Embedded Widgets Angular Elements is ideal for creating widgets that can be embedded in any website: - Analytics dashboards that can be embedded in content management systems - Interactive forms that can be placed on static websites - Third-party functionality that needs to be distributed as a script ### 2. Shared Component Libraries For organizations with multiple applications using different technologies: - Create a central component library using Angular - Export key components as web components - Use them consistently across all applications ### 3. Legacy Application Enhancement When working with older web applications: - Add modern functionality without rewriting the entire application - Incrementally enhance pages with interactive components - Bridge the gap between legacy systems and modern UX ### 4. Dynamic Content Systems For systems that load components at runtime: - Create a library of components that can be loaded based on user needs - Allow non-technical users to compose pages from pre-built components - Support extension through standardized component interfaces ## Benefits of This Approach ### For Angular Developers - Reuse components across different Angular applications - Package functionality for non-Angular projects - Create a consistent design system for your organization ### For Web Developers - Use powerful Angular components without adopting the entire framework - Integrate Angular components into any JavaScript framework (React, Vue, etc.) - Enhance static websites with dynamic Angular functionality ## Dependencies ### Production Dependencies - `@angular/core`: ^18.0.2 - Angular framework core - `@angular/elements`: ^18.0.2 - Angular Elements for web component creation - `@angular/common`, `@angular/forms`, `@angular/platform-browser`: Angular framework modules - `@memberjunction/core`: ^2.43.0 - MemberJunction core functionality - `@memberjunction/global`: ^2.43.0 - Global MemberJunction utilities and events - `@memberjunction/graphql-dataprovider`: ^2.43.0 - GraphQL data provider for MemberJunction - `@memberjunction/ng-user-view-grid`: ^2.43.0 - Angular grid component for user views - `rxjs`: ^7.8.1 - Reactive programming library - `zone.js`: ^0.14.0 - Angular's change detection mechanism ### Development Dependencies - `@angular-devkit/build-angular`: ^18.0.3 - Angular build tools - `@angular/cli`: ^18.0.3 - Angular command line interface - TypeScript, Karma, Jasmine for development and testing ## Integration with MemberJunction These components are designed to work with the MemberJunction framework: 1. **Authentication**: Components wait for the MemberJunction `LoggedIn` event before loading data 2. **Metadata System**: Components use MemberJunction's metadata system to access entity information 3. **GraphQL Integration**: Requires a configured GraphQL data provider for backend communication 4. **Event System**: Components use MemberJunction's global event system for internal communication ### Setting Up MemberJunction Connection ```javascript import { GraphQLProviderConfigData, setupGraphQLClient } from '@memberjunction/graphql-dataprovider'; // Configure and initialize the GraphQL client const config = new GraphQLProviderConfigData( jwtToken, // Your authentication token apiUrl, // e.g., 'http://localhost:4000' websocketUrl, // e.g., 'ws://localhost:4000/' schemaName // e.g., '__mj' ); await setupGraphQLClient(config); // Components will now automatically load data when ready ``` ## Configuration Options ### Angular Build Configuration The `angular.json` file is configured with: - **Output Hashing**: Disabled for consistent file names in bundles - **Budget Limits**: 20MB maximum for initial bundle (accommodates Angular framework) - **Polyfills**: Includes Zone.js for change detection ### Build Script Options The `build_angular_elements.sh` script supports: - Development builds: Faster builds with source maps - Production builds: Optimized and minified output - Custom configurations via Angular CLI flags ## Development ### Development Server ```bash ng serve # or npm run start ``` Navigate to `http://localhost:4200/`. The app will automatically reload if you change any source files. ### Testing ```bash # Run unit tests ng test # or npm run test ``` Tests are executed via [Karma](https://karma-runner.github.io) with Jasmine. ### Adding New Components 1. Create your Angular component as normal 2. Add it to the declarations in `app.module.ts` 3. Convert it to a custom element in the module constructor: ```typescript const element = createCustomElement(YourComponent, {injector}); customElements.define('your-element-name', element); ``` 4. Rebuild the bundle using `./build_angular_elements.sh` ## Troubleshooting ### Common Issues 1. **Components not rendering**: Ensure the bundle script is loaded before using the components 2. **No data loading**: Verify MemberJunction GraphQL client is properly initialized 3. **Events not firing**: Check that event listeners are attached after DOM is loaded 4. **Style conflicts**: Angular Elements uses Shadow DOM by default for style isolation ### Browser Compatibility - Modern browsers (Chrome, Firefox, Safari, Edge) have native support - For older browsers, include polyfills: ```html ``` ## License This package is part of the MemberJunction project. See the root LICENSE file for details. ## Learn More - [Angular Elements Documentation](https://angular.io/guide/elements) - [Web Components MDN](https://developer.mozilla.org/en-US/docs/Web/Web_Components) - [Custom Elements Specification](https://html.spec.whatwg.org/multipage/custom-elements.html) - [MemberJunction Documentation](https://docs.memberjunction.org)