Skip to content

Commit

Permalink
fix(io): invoke markForCheck when output handler is called
Browse files Browse the repository at this point in the history
Also use local injector in dynamic directives directive.

fixes #430
  • Loading branch information
ajafff committed Jan 16, 2021
1 parent d42111e commit 2a262d2
Show file tree
Hide file tree
Showing 6 changed files with 54 additions and 7 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -54,6 +54,7 @@ export interface DirectiveRef<T> {

@Directive({
selector: '[ndcDynamicDirectives],[ngComponentOutletNdcDynamicDirectives]',
providers: [IoFactoryService],
})
export class DynamicDirectivesDirective implements OnDestroy, DoCheck {
@Input()
Expand Down
Original file line number Diff line number Diff line change
@@ -1,5 +1,10 @@
// tslint:disable: no-string-literal
import { ChangeDetectorRef, SimpleChange, SimpleChanges } from '@angular/core';
import {
ChangeDetectionStrategy,
ChangeDetectorRef,
SimpleChange,
SimpleChanges,
} from '@angular/core';
import { async, ComponentFixture, TestBed } from '@angular/core/testing';
import { By } from '@angular/platform-browser';
import { Observable, Subject } from 'rxjs';
Expand Down Expand Up @@ -593,4 +598,35 @@ describe('Directive: DynamicIo', () => {
expect(outputHandler).toHaveBeenCalledWith('data');
});
});

describe('outputs with OnPush', () => {
function testOnPush(withArgs: boolean) {
const template = `<span [class]="value"></span><component-injector [ndcDynamicOutputs]="outputs"></component-injector>`;
TestBed.overrideComponent(TestComponent, {
set: { template, changeDetection: ChangeDetectionStrategy.OnPush },
});
const fixture = TestBed.createComponent(TestComponent);
const injectorComp = getComponentInjectorFrom(fixture).component;
const injectedComp = injectorComp.component;

const eventHandler = (v: string) =>
((fixture.componentInstance as any).value = v);
fixture.componentInstance['outputs'] = {
onEvent: withArgs ? { handler: eventHandler } : eventHandler,
};
fixture.detectChanges();
expect(fixture.nativeElement.querySelector('.foo')).toBeFalsy();
injectedComp.onEvent.emit('foo');
fixture.detectChanges();
expect(fixture.nativeElement.querySelector('.foo')).toBeTruthy();
}

it('should mark host component for check when calling event handler', () => {
testOnPush(false);
});

it('should mark host component for check when calling output with args', () => {
testOnPush(true);
});
});
});
Original file line number Diff line number Diff line change
@@ -1,11 +1,15 @@
import { ChangeDetectorRef } from '@angular/core';
import { inject, TestBed } from '@angular/core/testing';

import { IoFactoryService } from './io-factory.service';

describe('Service: IoFactory', () => {
beforeEach(() => {
TestBed.configureTestingModule({
providers: [IoFactoryService],
providers: [
IoFactoryService,
{ provide: ChangeDetectorRef, useValue: {} },
],
});
});

Expand Down
Original file line number Diff line number Diff line change
@@ -1,4 +1,5 @@
import {
ChangeDetectorRef,
ComponentFactoryResolver,
Inject,
Injectable,
Expand All @@ -8,16 +9,17 @@ import {
import { EventArgumentToken } from './event-argument';
import { IoService } from './io.service';

@Injectable({ providedIn: 'root' })
@Injectable()
export class IoFactoryService {
constructor(
private differs: KeyValueDiffers,
private cfr: ComponentFactoryResolver,
@Inject(EventArgumentToken)
private eventArgument: string,
private cdr: ChangeDetectorRef,
) {}

create() {
return new IoService(this.differs, this.cfr, this.eventArgument);
return new IoService(this.differs, this.cfr, this.eventArgument, this.cdr);
}
}
3 changes: 2 additions & 1 deletion projects/ng-dynamic-component/src/lib/io/io.service.spec.ts
Original file line number Diff line number Diff line change
@@ -1,3 +1,4 @@
import { ChangeDetectorRef } from '@angular/core';
import { TestBed } from '@angular/core/testing';

import { IoService } from './io.service';
Expand All @@ -7,7 +8,7 @@ describe('Service: Io', () => {

beforeEach(() => {
TestBed.configureTestingModule({
providers: [IoService],
providers: [IoService, { provide: ChangeDetectorRef, useValue: {} }],
});
service = TestBed.inject(IoService);
});
Expand Down
7 changes: 5 additions & 2 deletions projects/ng-dynamic-component/src/lib/io/io.service.ts
Original file line number Diff line number Diff line change
Expand Up @@ -74,6 +74,7 @@ export class IoService implements OnDestroy {
private cfr: ComponentFactoryResolver,
@Inject(EventArgumentToken)
private eventArgument: string,
private cdr: ChangeDetectorRef,
) {}

ngOnDestroy(): void {
Expand Down Expand Up @@ -166,7 +167,6 @@ export class IoService implements OnDestroy {
inputs = this._resolveInputs(inputs);

Object.keys(inputs).forEach(p => (compInst[p] = inputs[p]));

// Mark component for check to re-render with new inputs
if (this.compCdr) {
this.compCdr.markForCheck();
Expand All @@ -192,7 +192,10 @@ export class IoService implements OnDestroy {
.forEach(p =>
compInst[p]
.pipe(takeUntil(this.outputsShouldDisconnect$))
.subscribe((event: any) => (outputs[p] as EventHandler)(event)),
.subscribe((event: any) => {
this.cdr.markForCheck();
return (outputs[p] as EventHandler)(event);
}),
);
}

Expand Down

0 comments on commit 2a262d2

Please sign in to comment.