Skip to content

Commit

Permalink
fix(ng-dev): ComponentContextNext now handles inputs that come from…
Browse files Browse the repository at this point in the history
… a component's superclass

Closes #40
  • Loading branch information
ersimont committed Apr 28, 2021
1 parent 6c90588 commit f7830e6
Show file tree
Hide file tree
Showing 2 changed files with 42 additions and 6 deletions.
@@ -1,4 +1,10 @@
import { Component, ElementRef, Input, ViewChild } from '@angular/core';
import {
Component,
Directive,
ElementRef,
Input,
ViewChild,
} from '@angular/core';
import { By } from '@angular/platform-browser';
import { noop } from '@s-libs/micro-dash';
import { ComponentContextNext } from './component-context-next';
Expand Down Expand Up @@ -89,6 +95,27 @@ describe('createDynamicWrapper()', () => {
});
});

// https://github.com/simontonsoftware/s-libs/issues/40
it('can handle inputs defined by a superclass (production bug)', () => {
@Directive()
class SuperclassComponent {
@Input() superclassInput?: string;
}

@Component({ template: '' })
class SubclassComponent extends SuperclassComponent {
@Input() subclassInput?: string;
}

const ctx = new ComponentContextNext(SubclassComponent);
ctx.assignInputs({ superclassInput: 'an actual value' });
ctx.run(async () => {
expect(ctx.getComponentInstance().superclassInput).toBe(
'an actual value',
);
});
});

it('allows using default values for inputs', () => {
@Component({ template: '' })
class UnboundInputComponent {
Expand Down
@@ -1,7 +1,7 @@
import { Component, Type } from '@angular/core';
import { TestBed } from '@angular/core/testing';
import { assert } from '@s-libs/js-core';
import { flatMap } from '@s-libs/micro-dash';
import { forOwn } from '@s-libs/micro-dash';

/** @hidden */
interface InputMeta<T> {
Expand Down Expand Up @@ -74,19 +74,28 @@ function isValidSelector(selector: string): boolean {

/** @hidden */
function getInputMetas<T>(componentType: Type<T>): Array<InputMeta<T>> {
let metas: Array<InputMeta<T>>;
const superType = Object.getPrototypeOf(componentType.prototype)?.constructor;
if (superType) {
metas = getInputMetas(superType);
} else {
metas = [];
}

// I tried making this support inputs with special characters in their names, but it turns out that *Angular* can only support that when using AOT. So our *dynamic* wrapper cannot.
return flatMap(
forOwn(
(componentType as any).propDecorators,
(decorators: any[], property: any) => {
const inputDecorators = decorators.filter(
(decorator) => decorator.type.prototype.ngMetadataName === 'Input',
);
return inputDecorators.map((decorator) => {
for (const decorator of inputDecorators) {
const binding = decorator.args?.[0] || property;
return { property, binding };
});
metas.push({ property, binding });
}
},
);
return metas;
}

/** @hidden */
Expand Down

0 comments on commit f7830e6

Please sign in to comment.