Skip to content

Commit 628303d

Browse files
karaIgorMinar
authored andcommitted
fix(ivy): instantiate dirs in correct order (angular#23178)
PR Close angular#23178
1 parent d80e930 commit 628303d

File tree

8 files changed

+610
-142
lines changed

8 files changed

+610
-142
lines changed

packages/core/src/render3/di.ts

Lines changed: 23 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -19,7 +19,7 @@ import {EmbeddedViewRef as viewEngine_EmbeddedViewRef, ViewRef as viewEngine_Vie
1919
import {Type} from '../type';
2020

2121
import {assertLessThan, assertNotNull} from './assert';
22-
import {addToViewTree, assertPreviousIsParent, createLContainer, createLNodeObject, getDirectiveInstance, getPreviousOrParentNode, getRenderer, isComponent, renderEmbeddedTemplate} from './instructions';
22+
import {addToViewTree, assertPreviousIsParent, createLContainer, createLNodeObject, getDirectiveInstance, getPreviousOrParentNode, getRenderer, isComponent, renderEmbeddedTemplate, resolveDirective} from './instructions';
2323
import {ComponentTemplate, DirectiveDef} from './interfaces/definition';
2424
import {LInjector} from './interfaces/injector';
2525
import {LContainerNode, LElementNode, LNode, LNodeType, LViewNode, TNodeFlags} from './interfaces/node';
@@ -404,8 +404,15 @@ export function getOrCreateInjectable<T>(
404404
}
405405
}
406406

407-
// If we *didn't* find the directive for the token from the candidate injector, we had a false
408-
// positive. Traverse up the tree and continue.
407+
// If we *didn't* find the directive for the token and we are searching the current node's
408+
// injector, it's possible the directive is on this node and hasn't been created yet.
409+
let instance: T|null;
410+
if (injector === di && (instance = searchMatchesQueuedForCreation<T>(node, token))) {
411+
return instance;
412+
}
413+
414+
// The def wasn't found anywhere on this node, so it might be a false positive.
415+
// Traverse up the tree and continue searching.
409416
injector = injector.parent;
410417
}
411418
}
@@ -415,6 +422,19 @@ export function getOrCreateInjectable<T>(
415422
throw createInjectionError('Not found', token);
416423
}
417424

425+
function searchMatchesQueuedForCreation<T>(node: LNode, token: any): T|null {
426+
const matches = node.view.tView.currentMatches;
427+
if (matches) {
428+
for (let i = 0; i < matches.length; i += 2) {
429+
const def = matches[i] as DirectiveDef<any>;
430+
if (def.type === token) {
431+
return resolveDirective(def, i + 1, matches, node.view.tView);
432+
}
433+
}
434+
}
435+
return null;
436+
}
437+
418438
/**
419439
* Given a directive type, this function returns the bit in an injector's bloom filter
420440
* that should be used to determine whether or not the directive is present.

packages/core/src/render3/errors.ts

Lines changed: 35 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,35 @@
1+
2+
/**
3+
* @license
4+
* Copyright Google Inc. All Rights Reserved.
5+
*
6+
* Use of this source code is governed by an MIT-style license that can be
7+
* found in the LICENSE file at https://angular.io/license
8+
*/
9+
import {TNode} from './interfaces/node';
10+
11+
/** Called when directives inject each other (creating a circular dependency) */
12+
export function throwCyclicDependencyError(token: any): never {
13+
throw new Error(`Cannot instantiate cyclic dependency! ${token}`);
14+
}
15+
16+
/** Called when there are multiple component selectors that match a given node */
17+
export function throwMultipleComponentError(tNode: TNode): never {
18+
throw new Error(`Multiple components match node with tagname ${tNode.tagName}`);
19+
}
20+
21+
/** Throws an ExpressionChangedAfterChecked error if checkNoChanges mode is on. */
22+
export function throwErrorIfNoChangesMode(
23+
creationMode: boolean, checkNoChangesMode: boolean, oldValue: any, currValue: any): never|void {
24+
if (checkNoChangesMode) {
25+
let msg =
26+
`ExpressionChangedAfterItHasBeenCheckedError: Expression has changed after it was checked. Previous value: '${oldValue}'. Current value: '${currValue}'.`;
27+
if (creationMode) {
28+
msg +=
29+
` It seems like the view has been created after its parent and its children have been dirty checked.` +
30+
` Has it been created in a change detection hook ?`;
31+
}
32+
// TODO: include debug context
33+
throw new Error(msg);
34+
}
35+
}

0 commit comments

Comments
 (0)