Skip to content

Commit

Permalink
Merge pull request #2 from gund/beta
Browse files Browse the repository at this point in the history
Version 1
  • Loading branch information
gund authored Mar 25, 2017
2 parents 7a8a8d1 + 61aae93 commit 485728c
Show file tree
Hide file tree
Showing 5 changed files with 678 additions and 503 deletions.
23 changes: 21 additions & 2 deletions README.MD
Original file line number Diff line number Diff line change
Expand Up @@ -10,6 +10,9 @@
[![Licence](https://img.shields.io/npm/l/ng-dynamic-component.svg?maxAge=2592000)](https://github.com/gund/ng-dynamic-component/blob/master/LICENSE)
[![semantic-release](https://img.shields.io/badge/%20%20%F0%9F%93%A6%F0%9F%9A%80-semantic--release-e10079.svg)](https://github.com/semantic-release/semantic-release)

Version 1+ supports Angular 4+
For Angular 2 please use `ng-dynamic-component@^0.0.1`

## Installation

```bash
Expand Down Expand Up @@ -65,6 +68,24 @@ class MyComponent {
Here you can update your inputs (ex. `inputs.hello = 'WORLD'`) and they will trigger standard Angular's life-cycle hooks
(of course you should consider which change detection strategy you are using).


You can also use [`NgComponentOutlet`](https://angular.io/docs/ts/latest/api/common/index/NgComponentOutlet-directive.html)
directive from `@angular/common` instead of `<ndc-dynamic>` and apply `inputs` and `outputs` to your dynamic components:
```ts
@Component({
selector: 'my-component',
template: `<div *ngComponentOutlet="component"
[ndcDynamicInputs]="inputs"
[ndcDynamicOutputs]="outputs"
></div>`
})
class MyComponent {
component = MyDynamicComponent1;
inputs = {...};
outputs = {...}
}
```

You can have more advanced stuff over your dynamically rendered components like setting custom injector (`[ndcDynamicInjector]`)
or providing additional/overriding providers (`[ndcDynamicProviders]`) or both simultaneously
or projecting nodes (`[ndcDynamicContent]`).
Expand All @@ -78,8 +99,6 @@ Thanks to this separation you are able to connect inputs/outputs and life-cycle
dynamic components by implementing `ComponentInjector` and providing it via `DynamicModule.withComponents(null, [here])` in second argument.

It was done to be able to reuse [`NgComponentOutlet`](https://github.com/angular/angular/commit/8578682) added in Angular 4-beta.3.
> Due to update of implementation angular team hide `componentRef` by making it private so extending of that directive and
exposing `componentRef` to be public will be necessary but this will be done in this library.

## License

Expand Down
53 changes: 27 additions & 26 deletions package.json
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
{
"name": "ng-dynamic-component",
"version": "0.0.0-semantically-released",
"description": "Dynamic components with full life-cycle support for inputs and outputs",
"description": "Dynamic components with full life-cycle support for inputs and outputs for Angular",
"main": "dist/bundles/ng-dynamic-component.umd.js",
"module": "dist/index.js",
"scripts": {
Expand Down Expand Up @@ -35,24 +35,25 @@
"author": "Alex Malkevich <[email protected]>",
"license": "MIT",
"peerDependencies": {
"@angular/common": "^2.4.7",
"rxjs": "^5.1.0"
"@angular/core": "4.0.0",
"@angular/common": "4.0.0",
"rxjs": "^5.2.0"
},
"devDependencies": {
"@angular/common": "^2.4.7",
"@angular/compiler": "^2.4.7",
"@angular/compiler-cli": "^2.4.7",
"@angular/core": "^2.4.7",
"@angular/platform-browser": "^2.4.7",
"@angular/platform-browser-dynamic": "^2.4.7",
"@angular/platform-server": "^2.4.7",
"@angular/common": "4.0.0",
"@angular/compiler": "4.0.0",
"@angular/compiler-cli": "4.0.0",
"@angular/core": "4.0.0",
"@angular/platform-browser": "4.0.0",
"@angular/platform-browser-dynamic": "4.0.0",
"@angular/platform-server": "4.0.0",
"@types/jasmine": "^2.5.43",
"angular2-template-loader": "^0.6.2",
"awesome-typescript-loader": "^3.0.4",
"awesome-typescript-loader": "^3.1.2",
"codecov": "^1.0.1",
"codelyzer": "^2.0.0",
"commitizen": "^2.9.5",
"cz-conventional-changelog": "^1.2.0",
"codelyzer": "^3.0.0-beta.4",
"commitizen": "^2.9.6",
"cz-conventional-changelog": "^2.0.0",
"istanbul": "^0.4.5",
"jasmine-core": "^2.5.2",
"jasmine-spec-reporter": "^3.0.0",
Expand All @@ -66,25 +67,25 @@
"karma-remap-istanbul": "^0.4.0",
"karma-sourcemap-loader": "^0.3.7",
"karma-webpack": "^2.0.2",
"npm-run-all": "^4.0.0",
"npm-run-all": "^4.0.2",
"raw-loader": "^0.5.1",
"rimraf": "^2.5.4",
"rollup": "^0.41.4",
"rimraf": "^2.6.1",
"rollup": "^0.41.6",
"rollup-globals-regex": "^0.0.1",
"rollup-plugin-node-resolve": "^2.0.0",
"rxjs": "^5.1.0",
"rxjs": "^5.2.0",
"semantic-release": "^6.3.2",
"source-map": "^0.5.6",
"source-map-loader": "^0.1.5",
"source-map-loader": "^0.2.0",
"sourcemap-istanbul-instrumenter-loader": "^0.2.0",
"tslib": "^1.5.0",
"tslint": "^4.4.2",
"tslint-loader": "^3.4.2",
"typescript": "^2.2.0",
"tslib": "^1.6.0",
"tslint": "^4.5.1",
"tslint-loader": "^3.4.3",
"typescript": "^2.2.1",
"uglifyjs": "^2.4.10",
"webpack": "^2.2.1",
"webpack-dev-server": "^2.3.0",
"zone.js": "^0.7.7"
"webpack": "^2.3.2",
"webpack-dev-server": "^2.4.2",
"zone.js": "^0.8.5"
},
"engines": {
"node": ">=6.0.0"
Expand Down
29 changes: 22 additions & 7 deletions src/dynamic/dynamic.directive.ts
Original file line number Diff line number Diff line change
@@ -1,5 +1,6 @@
import { COMPONENT_INJECTOR, ComponentInjector } from './component-injector';
import { CustomSimpleChange, UNINITIALIZED } from './custom-simple-change';
import { NgComponentOutlet } from '@angular/common';
import {
Directive,
DoCheck,
Expand All @@ -10,10 +11,13 @@ import {
KeyValueDiffers,
OnChanges,
OnDestroy,
Optional,
SimpleChanges
} from '@angular/core';
import { Subject } from 'rxjs/Subject';

export type KeyValueChangeRecordAny = KeyValueChangeRecord<any, any>;

@Directive({
selector: '[ndcDynamicInputs], [ndcDynamicOutputs]'
})
Expand All @@ -22,14 +26,19 @@ export class DynamicDirective implements OnChanges, DoCheck, OnDestroy {
@Input() ndcDynamicInputs: { [k: string]: any } = {};
@Input() ndcDynamicOutputs: { [k: string]: Function } = {};

private _componentInjector: ComponentInjector = this._injector.get(this._componentInjectorType);
private _componentInjector: ComponentInjector = this._injector.get(this._componentInjectorType, {});
private _lastComponentInst: any = this._componentInjector;
private _lastInputChanges: SimpleChanges;
private _inputsDiffer = this._differs.find(this.ndcDynamicInputs).create(null);
private _destroyed$ = new Subject<void>();

private get _compOutletInst(): any {
return this._componentOutlet && (<any>this._componentOutlet)._componentRef;
}

private get _componentInst(): any {
return this._componentInjector.componentRef && this._componentInjector.componentRef.instance;
return this._compOutletInst ||
this._componentInjector.componentRef && this._componentInjector.componentRef.instance;
}

private get _componentInstChanged(): boolean {
Expand All @@ -44,7 +53,8 @@ export class DynamicDirective implements OnChanges, DoCheck, OnDestroy {
constructor(
private _differs: KeyValueDiffers,
private _injector: Injector,
@Inject(COMPONENT_INJECTOR) private _componentInjectorType: ComponentInjector
@Inject(COMPONENT_INJECTOR) private _componentInjectorType: ComponentInjector,
@Optional() private _componentOutlet: NgComponentOutlet
) { }

ngOnChanges(changes: SimpleChanges) {
Expand Down Expand Up @@ -103,6 +113,11 @@ export class DynamicDirective implements OnChanges, DoCheck, OnDestroy {
}

notifyOnInputChanges(changes: SimpleChanges = {}, forceFirstChanges: boolean) {
// Exit early if component not interrested to receive changes
if (!this._componentInst.ngOnChanges) {
return;
}

if (forceFirstChanges) {
changes = this._collectFirstChanges();
}
Expand All @@ -114,18 +129,18 @@ export class DynamicDirective implements OnChanges, DoCheck, OnDestroy {
const changes = {} as SimpleChanges;

Object.keys(this.ndcDynamicInputs).forEach(prop =>
changes[prop] = new CustomSimpleChange(UNINITIALIZED, this.ndcDynamicInputs[prop]));
changes[prop] = new CustomSimpleChange(UNINITIALIZED, this.ndcDynamicInputs[prop], true));

return changes;
}

private _collectChangesFromDiffer(differ: any): SimpleChanges {
const changes = {} as SimpleChanges;

differ.forEachItem((record: KeyValueChangeRecord) =>
changes[record.key] = new CustomSimpleChange(record.previousValue, record.currentValue));
differ.forEachItem((record: KeyValueChangeRecordAny) =>
changes[record.key] = new CustomSimpleChange(record.previousValue, record.currentValue, false));

differ.forEachAddedItem((record: KeyValueChangeRecord) =>
differ.forEachAddedItem((record: KeyValueChangeRecordAny) =>
changes[record.key].previousValue = UNINITIALIZED);

return changes;
Expand Down
5 changes: 2 additions & 3 deletions src/test/util.ts
Original file line number Diff line number Diff line change
@@ -1,13 +1,12 @@
import { Predicate } from '@angular/compiler/src/facade/collection';
import { DebugElement, Type } from '@angular/core';
import { ComponentFixture } from '@angular/core/testing';
import { By } from '@angular/platform-browser';

export function getByPredicate<T>(predicate: Predicate<DebugElement>) {
export function getByPredicate<T>(predicate: any) {
return (fixture: ComponentFixture<any>) => getCompFrom<T>(predicate, fixture);
}

export function getCompFrom<T>(predicate: Predicate<DebugElement>, fixture: ComponentFixture<any>) {
export function getCompFrom<T>(predicate: any, fixture: ComponentFixture<any>) {
const componentElem = fixture.debugElement.query(predicate);
const component = componentElem.componentInstance as T;
return { componentElem, component };
Expand Down
Loading

0 comments on commit 485728c

Please sign in to comment.