fix(ivy): throw meaningful error for uninitialized output (#28085)
Throws a similar error to ViewEngine when encountering an `@Output` that hasn't been initialized to an `Observable`. These changes resolve FW-680. PR Close #28085
This commit is contained in:
parent
693045165c
commit
da8ee29e72
@ -14,6 +14,7 @@ import {validateAttribute, validateProperty} from '../sanitization/sanitization'
|
|||||||
import {Sanitizer} from '../sanitization/security';
|
import {Sanitizer} from '../sanitization/security';
|
||||||
import {StyleSanitizeFn} from '../sanitization/style_sanitizer';
|
import {StyleSanitizeFn} from '../sanitization/style_sanitizer';
|
||||||
import {assertDataInRange, assertDefined, assertEqual, assertLessThan, assertNotEqual} from '../util/assert';
|
import {assertDataInRange, assertDefined, assertEqual, assertLessThan, assertNotEqual} from '../util/assert';
|
||||||
|
import {isObservable} from '../util/lang';
|
||||||
import {normalizeDebugBindingName, normalizeDebugBindingValue} from '../util/ng_reflect';
|
import {normalizeDebugBindingName, normalizeDebugBindingValue} from '../util/ng_reflect';
|
||||||
|
|
||||||
import {assertHasParent, assertPreviousIsParent} from './assert';
|
import {assertHasParent, assertPreviousIsParent} from './assert';
|
||||||
@ -936,7 +937,14 @@ export function listener(
|
|||||||
const declaredName = props[i++] as string;
|
const declaredName = props[i++] as string;
|
||||||
ngDevMode && assertDataInRange(lView, directiveIndex as number);
|
ngDevMode && assertDataInRange(lView, directiveIndex as number);
|
||||||
const directive = unwrapOnChangesDirectiveWrapper(lView[directiveIndex]);
|
const directive = unwrapOnChangesDirectiveWrapper(lView[directiveIndex]);
|
||||||
const subscription = directive[minifiedName].subscribe(listenerFn);
|
const output = directive[minifiedName];
|
||||||
|
|
||||||
|
if (ngDevMode && !isObservable(output)) {
|
||||||
|
throw new Error(
|
||||||
|
`@Output ${minifiedName} not initialized in '${directive.constructor.name}'.`);
|
||||||
|
}
|
||||||
|
|
||||||
|
const subscription = output.subscribe(listenerFn);
|
||||||
const idx = lCleanup.length;
|
const idx = lCleanup.length;
|
||||||
lCleanup.push(listenerFn, subscription);
|
lCleanup.push(listenerFn, subscription);
|
||||||
tCleanup && tCleanup.push(eventName, tNode.index, idx, -(idx + 1));
|
tCleanup && tCleanup.push(eventName, tNode.index, idx, -(idx + 1));
|
||||||
|
@ -347,22 +347,20 @@ function declareTests(config?: {useJit: boolean}) {
|
|||||||
expect(tc.injector.get(EventDir)).not.toBeNull();
|
expect(tc.injector.get(EventDir)).not.toBeNull();
|
||||||
});
|
});
|
||||||
|
|
||||||
fixmeIvy('FW-680: Throw meaningful error for uninitialized @Output')
|
it('should display correct error message for uninitialized @Output', () => {
|
||||||
.it('should display correct error message for uninitialized @Output', () => {
|
@Component({selector: 'my-uninitialized-output', template: '<p>It works!</p>'})
|
||||||
@Component({selector: 'my-uninitialized-output', template: '<p>It works!</p>'})
|
class UninitializedOutputComp {
|
||||||
class UninitializedOutputComp {
|
@Output() customEvent !: EventEmitter<any>;
|
||||||
@Output() customEvent !: EventEmitter<any>;
|
}
|
||||||
}
|
|
||||||
|
|
||||||
const template =
|
const template =
|
||||||
'<my-uninitialized-output (customEvent)="doNothing()"></my-uninitialized-output>';
|
'<my-uninitialized-output (customEvent)="doNothing()"></my-uninitialized-output>';
|
||||||
TestBed.overrideComponent(MyComp, {set: {template}});
|
TestBed.overrideComponent(MyComp, {set: {template}});
|
||||||
|
|
||||||
TestBed.configureTestingModule({declarations: [MyComp, UninitializedOutputComp]});
|
TestBed.configureTestingModule({declarations: [MyComp, UninitializedOutputComp]});
|
||||||
expect(() => TestBed.createComponent(MyComp))
|
expect(() => TestBed.createComponent(MyComp))
|
||||||
.toThrowError(
|
.toThrowError('@Output customEvent not initialized in \'UninitializedOutputComp\'.');
|
||||||
'@Output customEvent not initialized in \'UninitializedOutputComp\'.');
|
});
|
||||||
});
|
|
||||||
|
|
||||||
it('should read directives metadata from their binding token', () => {
|
it('should read directives metadata from their binding token', () => {
|
||||||
TestBed.configureTestingModule({declarations: [MyComp, PrivateImpl, NeedsPublicApi]});
|
TestBed.configureTestingModule({declarations: [MyComp, PrivateImpl, NeedsPublicApi]});
|
||||||
|
Loading…
x
Reference in New Issue
Block a user