From a6ba7895994c7f90353da32d4ffb2048df354898 Mon Sep 17 00:00:00 2001 From: Kristiyan Kostadinov Date: Wed, 9 Jan 2019 21:28:38 +0100 Subject: [PATCH] fix(ivy): init hooks being re-run if an exception is throw (#28024) Fixes Ivy running the init hooks if an exception is thrown in one of them. These changes fix FW-830. PR Close #28024 --- packages/core/src/render3/state.ts | 13 ++++-- .../change_detection_integration_spec.ts | 46 +++++++++---------- 2 files changed, 30 insertions(+), 29 deletions(-) diff --git a/packages/core/src/render3/state.ts b/packages/core/src/render3/state.ts index 69185a2340..a1d7f296f1 100644 --- a/packages/core/src/render3/state.ts +++ b/packages/core/src/render3/state.ts @@ -319,11 +319,14 @@ export function leaveView(newView: LView): void { if (isCreationMode(lView)) { lView[FLAGS] &= ~LViewFlags.CreationMode; } else { - executeHooks(lView, tView.viewHooks, tView.viewCheckHooks, checkNoChangesMode); - // Views are clean and in update mode after being checked, so these bits are cleared - lView[FLAGS] &= ~(LViewFlags.Dirty | LViewFlags.FirstLViewPass); - lView[FLAGS] |= LViewFlags.RunInit; - lView[BINDING_INDEX] = tView.bindingStartIndex; + try { + executeHooks(lView, tView.viewHooks, tView.viewCheckHooks, checkNoChangesMode); + } finally { + // Views are clean and in update mode after being checked, so these bits are cleared + lView[FLAGS] &= ~(LViewFlags.Dirty | LViewFlags.FirstLViewPass); + lView[FLAGS] |= LViewFlags.RunInit; + lView[BINDING_INDEX] = tView.bindingStartIndex; + } } enterView(newView, null); } diff --git a/packages/core/test/linker/change_detection_integration_spec.ts b/packages/core/test/linker/change_detection_integration_spec.ts index 9061d77010..197b8d6242 100644 --- a/packages/core/test/linker/change_detection_integration_spec.ts +++ b/packages/core/test/linker/change_detection_integration_spec.ts @@ -1022,33 +1022,31 @@ const TEST_COMPILER_PROVIDERS: Provider[] = [ expect(directiveLog.filter(['ngAfterViewInit'])).toEqual([]); })); - fixmeIvy( - 'FW-830: Exception thrown in ngAfterViewInit triggers ngAfterViewInit re-execution') - .it('should not call ngAfterViewInit again if it throws', fakeAsync(() => { - const ctx = createCompFixture( - '
'); + it('should not call ngAfterViewInit again if it throws', fakeAsync(() => { + const ctx = + createCompFixture('
'); - let errored = false; - // First pass fails, but ngAfterViewInit should be called. - try { - ctx.detectChanges(false); - } catch (e) { - errored = true; - } - expect(errored).toBe(true); + let errored = false; + // First pass fails, but ngAfterViewInit should be called. + try { + ctx.detectChanges(false); + } catch (e) { + errored = true; + } + expect(errored).toBe(true); - expect(directiveLog.filter(['ngAfterViewInit'])).toEqual(['dir.ngAfterViewInit']); - directiveLog.clear(); + expect(directiveLog.filter(['ngAfterViewInit'])).toEqual(['dir.ngAfterViewInit']); + directiveLog.clear(); - // Second change detection also fails, but this time ngAfterViewInit should not be - // called. - try { - ctx.detectChanges(false); - } catch (e) { - throw new Error('Second detectChanges() should not have run detection.'); - } - expect(directiveLog.filter(['ngAfterViewInit'])).toEqual([]); - })); + // Second change detection also fails, but this time ngAfterViewInit should not be + // called. + try { + ctx.detectChanges(false); + } catch (e) { + throw new Error('Second detectChanges() should not have run detection.'); + } + expect(directiveLog.filter(['ngAfterViewInit'])).toEqual([]); + })); }); describe('ngAfterViewChecked', () => {