{"id":13660811,"url":"https://github.com/dan-harris/ngx-loadable-component","last_synced_at":"2025-04-13T02:29:37.470Z","repository":{"id":118274647,"uuid":"139685920","full_name":"dan-harris/ngx-loadable-component","owner":"dan-harris","description":"Provides a simple interface for dynamic, lazy loadable components","archived":false,"fork":false,"pushed_at":"2019-02-24T01:06:32.000Z","size":311,"stargazers_count":11,"open_issues_count":1,"forks_count":1,"subscribers_count":2,"default_branch":"develop","last_synced_at":"2025-04-11T23:49:38.239Z","etag":null,"topics":["angular","angular-cli","typescript","typescript-library"],"latest_commit_sha":null,"homepage":"https://www.npmjs.com/package/ngx-loadable-component","language":"TypeScript","has_issues":true,"has_wiki":null,"has_pages":null,"mirror_url":null,"source_name":null,"license":"mit","status":null,"scm":"git","pull_requests_enabled":true,"icon_url":"https://github.com/dan-harris.png","metadata":{"files":{"readme":"README.md","changelog":null,"contributing":null,"funding":null,"license":"LICENSE","code_of_conduct":null,"threat_model":null,"audit":null,"citation":null,"codeowners":null,"security":null,"support":null,"governance":null,"roadmap":null,"authors":null}},"created_at":"2018-07-04T07:35:41.000Z","updated_at":"2020-04-30T09:20:26.000Z","dependencies_parsed_at":"2023-04-21T15:08:36.471Z","dependency_job_id":null,"html_url":"https://github.com/dan-harris/ngx-loadable-component","commit_stats":{"total_commits":20,"total_committers":2,"mean_commits":10.0,"dds":"0.050000000000000044","last_synced_commit":"acfd86416f2086da9b2f1474bcbe3b7cbd79c367"},"previous_names":[],"tags_count":5,"template":false,"template_full_name":null,"repository_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/dan-harris%2Fngx-loadable-component","tags_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/dan-harris%2Fngx-loadable-component/tags","releases_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/dan-harris%2Fngx-loadable-component/releases","manifests_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/dan-harris%2Fngx-loadable-component/manifests","owner_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners/dan-harris","download_url":"https://codeload.github.com/dan-harris/ngx-loadable-component/tar.gz/refs/heads/develop","host":{"name":"GitHub","url":"https://github.com","kind":"github","repositories_count":248657790,"owners_count":21140841,"icon_url":"https://github.com/github.png","version":null,"created_at":"2022-05-30T11:31:42.601Z","updated_at":"2022-07-04T15:15:14.044Z","host_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub","repositories_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories","repository_names_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repository_names","owners_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners"}},"keywords":["angular","angular-cli","typescript","typescript-library"],"created_at":"2024-08-02T05:01:26.006Z","updated_at":"2025-04-13T02:29:37.447Z","avatar_url":"https://github.com/dan-harris.png","language":"TypeScript","funding_links":[],"categories":["TypeScript"],"sub_categories":[],"readme":"![ngx-loadable-component](https://github.com/dan-harris/ngx-loadable-component/raw/master/logo.png)\n\nDynamically lazy load \u0026 code-split your Angular components.\n\n![](https://badgen.net/npm/v/ngx-loadable-component) ![](https://badgen.net/bundlephobia/minzip/ngx-loadable-component) ![](https://img.shields.io/badge/angular-v6%20%7C%20v7-red.svg) ![](https://badgen.net/github/license/dan-harris/ngx-loadable-component) ![](https://img.shields.io/badge/awesome-yes%20%F0%9F%91%8D-bb0073.svg)\n\n(Supports Angular 6+)\n\nCore functionality derived _heavily_ from [dynamically loading components with angular-cli](https://blog.angularindepth.com/dynamically-loading-components-with-angular-cli-92a3c69bcd28)\n\n## Easily 💤 lazy load \u0026 ⚡ code-split, components in 🅰 Angular\n\n🚧 no mucking around with seperate build processes\n\n💤 lazy load components\n\n🆓 free code splitting via Angular\n\n⚡ [demo](https://ngx-loadable-component-app-chfnxlwwxx.now.sh/)\n\n🤓 ingenious core pattern thought up by _[actual smart people](https://blog.angularindepth.com/dynamically-loading-components-with-angular-cli-92a3c69bcd28)_\n\n👌 created for the use case of seperating large single components (such as wysiwg editors, charts .etc) from the rest of your app code.\n\n# Installation\n\nInstall via npm;\n\n```\nnpm i ngx-loadable-component\n```\n\n_\\* unfortunately, only an aot build angular setup will work correctly within the **loadable component** setup 🤷 ️ .. an example of how this is setup can be seen within the base directory of this repo(app demo)_\n\n# Setup\n\nCreate a component you wish to dynamically load... e.g. **loadable component**\n\n_upside-down-face-emoji.component.ts_\n\n```typescript\n@Component({\n  selector: 'app-upside-down-face-emoji'\n  ...\n})\nexport class UpsideDownFaceEmojiComponent { }\n```\n\n_\\* its important that this component does not use `OnPush` changeDetection as this will interfere with the **loadable component** setup_\n\nThen create a module for the **loadable component**:\n\n_upside-down-face-emoji.module.ts_\n\n```typescript\nimport { LoadableComponentModule } from 'ngx-loadable-component';\n\nimport { UpsideDownFaceEmojiComponent } from './upside-down-face-emoji.component';\n\n@NgModule({\n  imports: [\n    // register as loadable component\n    LoadableComponentModule.forChild(UpsideDownFaceEmojiComponent)\n  ],\n  declarations: [UpsideDownFaceEmojiComponent]\n})\nexport class UpsideDownFaceEmojiComponentModule {}\n```\n\nCreate a **manifest** file which lists all your **loadable components**:\n\n_app-loadable.manifests.ts_\n\n```typescript\nimport { LoadableManifest } from 'ngx-loadable-component';\n\nexport enum LoadableComponentIds {\n  UPSIDE_DOWN_FACE = 'UpsideDownFaceEmojiComponent'\n}\n\nexport const appLoadableManifests: Array\u003cLoadableManifest\u003e = [\n  {\n    // used to retrieve the loadable component later\n    componentId: LoadableComponentIds.UPSIDE_DOWN_FACE,\n    // must be a unique value within the app...\n    // but apart from that only used by angular when loading component\n    path: `loadable-${LoadableComponentIds.UPSIDE_DOWN_FACE}`,\n    // relative path to component module\n    loadChildren: './components/upside-down-face-emoji/upside-down-face-emoji.module#UpsideDownFaceEmojiComponentModule'\n  }\n];\n```\n\nAdd the **loadable component manifest** \u0026 **loadable component module** to root app module:\n\n_app.module.ts_\n\n```typescript\nimport { LoadableComponentModule } from 'ngx-loadable-component';\n\n// loadable components manifest\nimport { appLoadableManifests } from './app-loadable.manifests';\n\n@NgModule({\n  declarations: [\n      ...\n  ],\n  imports: [\n    ...\n    // components to load as seperate async\n    LoadableComponentModule.forRoot(appLoadableManifests)\n  ],\n  providers: [],\n  bootstrap: [AppComponent]\n})\nexport class AppModule { }\n```\n\nBe sure to import the **loadable component module** into any feature modules you use it in:\n\n_my-feature.module.ts_\n\n```typescript\nimport { LoadableComponentModule } from 'ngx-loadable-component';\n\n@NgModule({\n  declarations: [\n      ...\n  ],\n  imports: [\n    ...\n    LoadableComponentModule.forFeature()\n  ]\n})\nexport class MyFeatureModule { }\n```\n\n# Usage (basic)\n\nAdd a **loadable component** where needed:\n\n_app.component.html_\n\n```html\n\u003cdiv class=\"app--emojis\"\u003e\n\n    \u003cloadable-component [componentId]=\"UPSIDE_DOWN_FACE_COMPONENT_ID\" [loadComponent]=\"loadUpsideDownFaceComponent\"\u003e\n        \u003c!-- any element in the loadable component content area will only be shown whilst loadComponent is false --\u003e\n        \u003capp-placeholder-emoji\u003e\u003c/app-placeholder-emoji\u003e\n    \u003c/loadable-component\u003e\n\n\u003c/div\u003e\n```\n\n_app.component.ts_\n\n```typescript\nimport { LoadableComponentIds } from '../../app-loadable.manifests';\n\n@Component({ ... })\nexport class AppComponent {\n  // loadable component ids\n  UPSIDE_DOWN_FACE_COMPONENT_ID: string = LoadableComponentIds.UPSIDE_DOWN_FACE;\n\n  // flags to load components\n  // setting this to 'true' will cause the loadable component\n  // to load the specified component id\n  loadUpsideDownFaceComponent: boolean = false;\n}\n```\n\n# Usage (with Inputs/Outputs)\n\nIf our **loadable component** has inputs/outputs - like so:\n\n_upside-down-face-emoji.component.html_\n\n```html\n\u003ca (click)=\"onClick()\"\u003e\n    \u003cdiv\u003e🙃\u003c/div\u003e\n    \u003cdiv\u003e{{ text }}\u003c/div\u003e\n\u003c/a\u003e\n```\n\n_upside-down-face-emoji.component.ts_\n\n```typescript\nexport class UpsideDownFaceEmojiComponent {\n  @Input() text: string = 'upside down';\n\n  @Output() clicked: EventEmitter\u003cstring\u003e = new EventEmitter\u003cstring\u003e();\n\n  constructor() {}\n\n  onClick(): void {\n    this.clicked.emit(this.text);\n  }\n}\n```\n\nWe then create a model representing the inputs/outputs (for some typing goodness 💯):\n\n_upside-down-face-emoji.inputs.model.ts_\n\n```typescript\nimport { LoadableComponentInputs } from 'ngx-loadable-component';\n\nexport interface UpsideDownFaceEmojiComponentInputs extends LoadableComponentInputs {\n  text: string;\n}\n```\n\n_upside-down-face-emoji.outputs.model.ts_\n\n```typescript\nimport { LoadableComponentOutputs } from 'ngx-loadable-component';\n\nexport interface UpsideDownFaceEmojiComponentOutputs extends LoadableComponentOutputs {\n  clicked: Function;\n}\n```\n\nAnd add our inputs/outputs to the **loadable component** wherever its used:\n\n_app.component.html_\n\n```html\n\u003cdiv class=\"app--emojis\"\u003e\n\n    \u003cloadable-component\n        [componentId]=\"UPSIDE_DOWN_FACE_COMPONENT_ID\"\n        [loadComponent]=\"loadUpsideDownFaceComponent\"\n        [componentInputs]=\"upsideDownFaceInputs\"\n        [componentOutputs]=\"upsideDownFaceOutputs\"\u003e\n        \u003c!-- any element in the loadable component content area will only be shown whilst loadComponent is false --\u003e\n        \u003capp-placeholder-emoji\u003e\u003c/app-placeholder-emoji\u003e\n    \u003c/loadable-component\u003e\n\n\u003c/div\u003e\n```\n\n_app.component.ts_\n\n```typescript\nimport { LoadableComponentIds } from '../../app-loadable.manifests';\nimport { UpsideDownFaceEmojiComponentInputs } from '../../components/upside-down-face-emoji/models/upside-down-face-emoji.inputs.model';\nimport { UpsideDownFaceEmojiComponentOutputs } from '../../components/upside-down-face-emoji/models/upside-down-face-emoji.outputs.model';\n\n@Component({ ... })\nexport class AppComponent {\n  // loadable component ids\n  UPSIDE_DOWN_FACE_COMPONENT_ID: string = LoadableComponentIds.UPSIDE_DOWN_FACE;\n\n  // flags to load components\n  // setting this to 'true' will cause the loadable component\n  // to load the specified component id\n  loadUpsideDownFaceComponent: boolean = false;\n\n  // inputs for loadable component\n  get upsideDownFaceInputs(): UpsideDownFaceEmojiComponentInputs {\n    return {\n      text: 'not upside down'\n    }\n  }\n\n  // outputs for loadable component\n  get upsideDownFaceOutputs(): UpsideDownFaceEmojiComponentOutputs {\n    return {\n      clicked: (text: string) =\u003e this.onClickedUpsideDownFace(text)\n    }\n  }\n\n  onClickedUpsideDownFace(text: string): void {\n    console.log('🖱', text);\n  }\n}\n```\n\nAnd voila! we now have input/output binding 👌.\n_\\* note that the inputs in the parent component (of the loadable component - e.g. `upsideDownFaceInputs()`) have to be within a getter or function for change detection to apply correctly_\n\n# Usage (add custom css classes)\n\nCustom css classes can be passed via the _loadable component_ `componentCssClasses` input.\nThese will be added to the host element of the provided loadable component. e.g.\n\n_app.component.html_\n\n```html\n\u003cdiv class=\"app--emojis\"\u003e\n\n    \u003cloadable-component ... [componentCssClasses]=\"customCssClasses\" \u003e\n        ...\n    \u003c/loadable-component\u003e\n\n\u003c/div\u003e\n```\n\n_app.component.ts_\n\n```typescript\n@Component({ ... })\nexport class AppComponent {\n  ...\n  // custom css classes\n  customCssClasses: Array\u003cstring\u003e = ['my-custom--class--1', 'my-custom--class--2']\n  ...\n}\n```\n\n# Author\n\n🤔 created by Dan Harris\n\n👨‍💻 website: [danharris.io](https://danharris.io)\n\n🐤 twitter: [@danharris_io](http://twitter.com/danharris_io)\n\n☕ made with love and late nights\n\n🤷‍ this package works well for my use case... no guarantees made to its general use\n\n# Odds \u0026 Ends\n\n👀 MIT License\n\n💖 if you've read this far... thanks for the star\n\n😎 title font courtesy of the awesome [lazer84 font](http://sunrise-digital.net/lazer84/)\n\n😡 please send all abusive letters via handwritten note to [this address](https://www.youtube.com/watch?v=dQw4w9WgXcQ)\n\n📫 all constructive feedback welcome.\n","project_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fdan-harris%2Fngx-loadable-component","html_url":"https://awesome.ecosyste.ms/projects/github.com%2Fdan-harris%2Fngx-loadable-component","lists_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fdan-harris%2Fngx-loadable-component/lists"}