Skip to content

Commit 409b630

Browse files
committed
0f774df fix(compiler): project using the right directive as component.
1 parent 286e780 commit 409b630

18 files changed

+133
-75
lines changed

BUILD_INFO

+2-2
Original file line numberDiff line numberDiff line change
@@ -1,2 +1,2 @@
1-
Sat Apr 30 01:44:32 UTC 2016
2-
5ff31f0713554440ccc91a57d7b52d7209096a10
1+
Sat Apr 30 03:04:37 UTC 2016
2+
0f774df81150524c399161272a6cd51d0d54aa7e

lib/src/compiler/identifiers.dart

+12
Original file line numberDiff line numberDiff line change
@@ -12,6 +12,8 @@ import "package:angular2/src/core/linker/view_utils.dart"
1212
interpolate,
1313
checkBinding,
1414
castByValue,
15+
EMPTY_ARRAY,
16+
EMPTY_MAP,
1517
pureProxy1,
1618
pureProxy2,
1719
pureProxy3,
@@ -84,6 +86,8 @@ var impDevModeEqual = devModeEqual;
8486
var impInterpolate = interpolate;
8587
var impCheckBinding = checkBinding;
8688
var impCastByValue = castByValue;
89+
var impEMPTY_ARRAY = EMPTY_ARRAY;
90+
var impEMPTY_MAP = EMPTY_MAP;
8791

8892
class Identifiers {
8993
static var ViewUtils = new CompileIdentifierMetadata(
@@ -199,6 +203,14 @@ class Identifiers {
199203
name: "castByValue",
200204
moduleUrl: VIEW_UTILS_MODULE_URL,
201205
runtime: impCastByValue);
206+
static var EMPTY_ARRAY = new CompileIdentifierMetadata(
207+
name: "EMPTY_ARRAY",
208+
moduleUrl: VIEW_UTILS_MODULE_URL,
209+
runtime: impEMPTY_ARRAY);
210+
static var EMPTY_MAP = new CompileIdentifierMetadata(
211+
name: "EMPTY_MAP",
212+
moduleUrl: VIEW_UTILS_MODULE_URL,
213+
runtime: impEMPTY_MAP);
202214
static var pureProxies = [
203215
null,
204216
new CompileIdentifierMetadata(

lib/src/compiler/template_ast.dart

-13
Original file line numberDiff line numberDiff line change
@@ -158,19 +158,6 @@ class ElementAst implements TemplateAst {
158158
dynamic visit(TemplateAstVisitor visitor, dynamic context) {
159159
return visitor.visitElement(this, context);
160160
}
161-
162-
/**
163-
* Get the component associated with this element, if any.
164-
*/
165-
CompileDirectiveMetadata getComponent() {
166-
for (var i = 0; i < this.directives.length; i++) {
167-
var dirAst = this.directives[i];
168-
if (dirAst.directive.isComponent) {
169-
return dirAst.directive;
170-
}
171-
}
172-
return null;
173-
}
174161
}
175162

176163
/**

lib/src/compiler/template_parser.dart

+5-3
Original file line numberDiff line numberDiff line change
@@ -1011,9 +1011,11 @@ class ElementContext {
10111011
List<DirectiveAst> directives, ProviderElementContext providerContext) {
10121012
var matcher = new SelectorMatcher();
10131013
var wildcardNgContentIndex = null;
1014-
if (directives.length > 0 && directives[0].directive.isComponent) {
1015-
var ngContentSelectors =
1016-
directives[0].directive.template.ngContentSelectors;
1014+
var component = directives.firstWhere(
1015+
(directive) => directive.directive.isComponent,
1016+
orElse: () => null);
1017+
if (isPresent(component)) {
1018+
var ngContentSelectors = component.directive.template.ngContentSelectors;
10171019
for (var i = 0; i < ngContentSelectors.length; i++) {
10181020
var selector = ngContentSelectors[i];
10191021
if (StringWrapper.equals(selector, "*")) {

lib/src/compiler/view_compiler/compile_element.dart

+2-1
Original file line numberDiff line numberDiff line change
@@ -388,7 +388,8 @@ class CompileElement extends CompileNode {
388388
if (identical(requestingProviderType, ProviderAstType.Component)) {
389389
return this._compViewExpr.prop("ref");
390390
} else {
391-
return o.THIS_EXPR.prop("ref");
391+
return getPropertyInView(
392+
o.THIS_EXPR.prop("ref"), this.view, this.view.componentView);
392393
}
393394
}
394395
}

lib/src/compiler/view_compiler/compile_pipe.dart

+2-1
Original file line numberDiff line numberDiff line change
@@ -33,7 +33,8 @@ class CompilePipe {
3333
var deps = this.meta.type.diDeps.map((diDep) {
3434
if (diDep.token
3535
.equalsTo(identifierToken(Identifiers.ChangeDetectorRef))) {
36-
return o.THIS_EXPR.prop("ref");
36+
return getPropertyInView(
37+
o.THIS_EXPR.prop("ref"), this.view, this.view.componentView);
3738
}
3839
return injectFromViewParentInjector(diDep.token, false);
3940
}).toList();

lib/src/compiler/view_compiler/compile_view.dart

+7
Original file line numberDiff line numberDiff line change
@@ -27,6 +27,7 @@ import "util.dart"
2727
createPureProxy;
2828
import "../config.dart" show CompilerConfig;
2929
import "compile_binding.dart" show CompileBinding;
30+
import "../identifiers.dart" show Identifiers;
3031

3132
class CompileView implements NameResolver {
3233
CompileDirectiveMetadata component;
@@ -159,6 +160,9 @@ class CompileView implements NameResolver {
159160
}
160161

161162
o.Expression createLiteralArray(List<o.Expression> values) {
163+
if (identical(values.length, 0)) {
164+
return o.importExpr(Identifiers.EMPTY_ARRAY);
165+
}
162166
var proxyExpr =
163167
o.THIS_EXPR.prop('''_arr_${ this . literalArrayCount ++}''');
164168
List<o.FnParam> proxyParams = [];
@@ -179,6 +183,9 @@ class CompileView implements NameResolver {
179183

180184
o.Expression createLiteralMap(
181185
List<List<dynamic /* String | o . Expression */ >> entries) {
186+
if (identical(entries.length, 0)) {
187+
return o.importExpr(Identifiers.EMPTY_MAP);
188+
}
182189
var proxyExpr = o.THIS_EXPR.prop('''_map_${ this . literalMapCount ++}''');
183190
List<o.FnParam> proxyParams = [];
184191
List<List<dynamic /* String | o . Expression */ >> proxyReturnEntries = [];

lib/src/compiler/view_compiler/event_binder.dart

+6-12
Original file line numberDiff line numberDiff line change
@@ -103,12 +103,9 @@ class CompileEventListener {
103103
listenToRenderer() {
104104
var listenExpr;
105105
var eventListener = o.THIS_EXPR.callMethod("eventHandler", [
106-
o.fn([
107-
this._eventParam
108-
], [
109-
new o.ReturnStatement(
110-
o.THIS_EXPR.callMethod(this._methodName, [EventHandlerVars.event]))
111-
], o.BOOL_TYPE)
106+
o.THIS_EXPR
107+
.prop(this._methodName)
108+
.callMethod(o.BuiltinMethod.bind, [o.THIS_EXPR])
112109
]);
113110
if (isPresent(this.eventTarget)) {
114111
listenExpr = ViewProperties.renderer.callMethod("listenGlobal", [
@@ -136,12 +133,9 @@ class CompileEventListener {
136133
'''subscription_${ this . compileElement . view . subscriptions . length}''');
137134
this.compileElement.view.subscriptions.add(subscription);
138135
var eventListener = o.THIS_EXPR.callMethod("eventHandler", [
139-
o.fn([
140-
this._eventParam
141-
], [
142-
o.THIS_EXPR
143-
.callMethod(this._methodName, [EventHandlerVars.event]).toStmt()
144-
])
136+
o.THIS_EXPR
137+
.prop(this._methodName)
138+
.callMethod(o.BuiltinMethod.bind, [o.THIS_EXPR])
145139
]);
146140
this.compileElement.view.createMethod.addStmt(subscription
147141
.set(directiveInstance

lib/src/compiler/view_compiler/view_builder.dart

+2-1
Original file line numberDiff line numberDiff line change
@@ -215,9 +215,10 @@ class ViewBuilderVisitor implements TemplateAstVisitor {
215215
this.view.createMethod.addStmt(
216216
o.THIS_EXPR.prop(fieldName).set(createRenderNodeExpr).toStmt());
217217
var renderNode = o.THIS_EXPR.prop(fieldName);
218-
var component = ast.getComponent();
219218
var directives =
220219
ast.directives.map((directiveAst) => directiveAst.directive).toList();
220+
var component = directives.firstWhere((directive) => directive.isComponent,
221+
orElse: () => null);
221222
var htmlAttrs = _readHtmlAttrs(ast.attrs);
222223
var attrNameAndValues = _mergeHtmlAndDirectiveAttrs(htmlAttrs, directives);
223224
for (var i = 0; i < attrNameAndValues.length; i++) {

lib/src/core/linker/component_factory.dart

+1-1
Original file line numberDiff line numberDiff line change
@@ -92,7 +92,7 @@ class ComponentRef_ extends ComponentRef {
9292
}
9393

9494
ChangeDetectorRef get changeDetectorRef {
95-
return this.hostView;
95+
return this._hostElement.parentView.ref;
9696
}
9797

9898
Type get componentType {

lib/src/core/linker/view.dart

+4-15
Original file line numberDiff line numberDiff line change
@@ -70,7 +70,6 @@ abstract class AppView<T> {
7070
List<dynamic> subscriptions;
7171
List<AppView<dynamic>> contentChildren = [];
7272
List<AppView<dynamic>> viewChildren = [];
73-
AppView<dynamic> renderParent;
7473
AppElement viewContainerElement = null;
7574
// The names of the below fields must be kept in sync with codegen_name_util.ts or
7675

@@ -136,7 +135,6 @@ abstract class AppView<T> {
136135

137136
// in the ViewFactory already.
138137
this.declarationAppElement.parentView.viewChildren.add(this);
139-
this.renderParent = this.declarationAppElement.parentView;
140138
this.dirtyParentQueriesInternal();
141139
}
142140
}
@@ -254,18 +252,6 @@ abstract class AppView<T> {
254252
* Overwritten by implementations
255253
*/
256254
void dirtyParentQueriesInternal() {}
257-
void addRenderContentChild(AppView<dynamic> view) {
258-
this.contentChildren.add(view);
259-
view.renderParent = this;
260-
view.dirtyParentQueriesInternal();
261-
}
262-
263-
void removeContentChild(AppView<dynamic> view) {
264-
ListWrapper.remove(this.contentChildren, view);
265-
view.dirtyParentQueriesInternal();
266-
view.renderParent = null;
267-
}
268-
269255
void detectChanges(bool throwOnChange) {
270256
var s = _scope_check(this.clazz);
271257
if (identical(this.cdMode, ChangeDetectionStrategy.Detached) ||
@@ -324,7 +310,10 @@ abstract class AppView<T> {
324310
if (identical(c.cdMode, ChangeDetectionStrategy.Checked)) {
325311
c.cdMode = ChangeDetectionStrategy.CheckOnce;
326312
}
327-
c = c.renderParent;
313+
var parentEl = identical(c.type, ViewType.COMPONENT)
314+
? c.declarationAppElement
315+
: c.viewContainerElement;
316+
c = isPresent(parentEl) ? parentEl.parentView : null;
328317
}
329318
}
330319

lib/src/core/linker/view_ref.dart

+2-16
Original file line numberDiff line numberDiff line change
@@ -7,14 +7,7 @@ import "view.dart" show AppView;
77
import "package:angular2/src/core/change_detection/constants.dart"
88
show ChangeDetectionStrategy;
99

10-
abstract class ViewRef extends ChangeDetectorRef {
11-
/**
12-
* @internal
13-
*/
14-
ChangeDetectorRef get changeDetectorRef {
15-
return (unimplemented() as ChangeDetectorRef);
16-
}
17-
10+
abstract class ViewRef {
1811
bool get destroyed {
1912
return (unimplemented() as bool);
2013
}
@@ -90,7 +83,7 @@ abstract class EmbeddedViewRef<C> extends ViewRef {
9083
destroy();
9184
}
9285

93-
class ViewRef_<C> implements EmbeddedViewRef<C> {
86+
class ViewRef_<C> implements EmbeddedViewRef<C>, ChangeDetectorRef {
9487
AppView<C> _view;
9588
ViewRef_(this._view) {
9689
this._view = _view;
@@ -99,13 +92,6 @@ class ViewRef_<C> implements EmbeddedViewRef<C> {
9992
return this._view;
10093
}
10194

102-
/**
103-
* Return `ChangeDetectorRef`
104-
*/
105-
ChangeDetectorRef get changeDetectorRef {
106-
return this;
107-
}
108-
10995
List<dynamic> get rootNodes {
11096
return this._view.flatRootNodes;
11197
}

lib/src/core/linker/view_utils.dart

+2
Original file line numberDiff line numberDiff line change
@@ -256,6 +256,8 @@ dynamic/*= T */ castByValue/*< T >*/(dynamic input, dynamic/*= T */ value) {
256256
return (input as dynamic/*= T */);
257257
}
258258

259+
const EMPTY_ARRAY = const [];
260+
const EMPTY_MAP = const {};
259261
dynamic /* (p0: P0) => R */ pureProxy1/*< P0, R >*/(
260262
dynamic/*= R */ fn(dynamic/*= P0 */ p0)) {
261263
dynamic/*= R */ result;

test/compiler/template_parser_spec.dart

+16
Original file line numberDiff line numberDiff line change
@@ -1093,6 +1093,13 @@ There is no directive with "exportAs" set to "dirA" ("<div [ERROR ->]#a="dirA"><
10931093
template: new CompileTemplateMetadata(
10941094
ngContentSelectors: ngContentSelectors));
10951095
}
1096+
CompileDirectiveMetadata createDir(String selector) {
1097+
return CompileDirectiveMetadata.create(
1098+
selector: selector,
1099+
type: new CompileTypeMetadata(
1100+
moduleUrl: someModuleUrl,
1101+
name: '''SomeDir${ compCounter ++}'''));
1102+
}
10961103
describe("project text nodes", () {
10971104
it("should project text nodes with wildcard selector", () {
10981105
expect(humanizeContentProjection(parse("<div>hello</div>", [
@@ -1268,6 +1275,15 @@ There is no directive with "exportAs" set to "dirA" ("<div [ERROR ->]#a="dirA"><
12681275
]);
12691276
});
12701277
});
1278+
it("should support other directives before the component", () {
1279+
expect(humanizeContentProjection(parse("<div>hello</div>", [
1280+
createDir("div"),
1281+
createComp("div", ["*"])
1282+
]))).toEqual([
1283+
["div", null],
1284+
["#text(hello)", 0]
1285+
]);
1286+
});
12711287
});
12721288
describe("splitClasses", () {
12731289
it("should keep an empty class", () {

test/core/linker/change_detection_integration_spec.dart

+10
Original file line numberDiff line numberDiff line change
@@ -335,6 +335,11 @@ main() {
335335
[1, 2]
336336
]);
337337
}));
338+
it("should support empty literal array", fakeAsync(() {
339+
var ctx = _bindSimpleValue("[]");
340+
ctx.detectChanges(false);
341+
expect(renderLog.loggedValues).toEqual([[]]);
342+
}));
338343
it("should support literal array made of expressions", fakeAsync(() {
339344
var ctx = _bindSimpleValue("[1, a]", TestData);
340345
ctx.componentInstance.a = 2;
@@ -362,6 +367,11 @@ main() {
362367
ctx.detectChanges(false);
363368
expect(renderLog.loggedValues[0]["z"]).toEqual(1);
364369
}));
370+
it("should support empty literal map", fakeAsync(() {
371+
var ctx = _bindSimpleValue("{}");
372+
ctx.detectChanges(false);
373+
expect(renderLog.loggedValues).toEqual([{}]);
374+
}));
365375
it("should support literal maps made of expressions", fakeAsync(() {
366376
var ctx = _bindSimpleValue("{z: a}");
367377
ctx.componentInstance.a = 1;

test/core/linker/integration_spec.dart

+26-4
Original file line numberDiff line numberDiff line change
@@ -871,13 +871,27 @@ declareTests(bool isJit) {
871871
]))
872872
.createAsync(MyComp)
873873
.then((fixture) {
874-
var cmp = fixture.debugElement.children[0].references["cmp"];
875-
fixture.debugElement.componentInstance.ctxProp = "one";
874+
var cmpEl = fixture.debugElement.children[0];
875+
var cmp = cmpEl.componentInstance;
876+
fixture.detectChanges();
876877
fixture.detectChanges();
877878
expect(cmp.numberOfChecks).toEqual(1);
878-
fixture.debugElement.componentInstance.ctxProp = "two";
879+
cmpEl.children[0].triggerEventHandler("click", ({} as dynamic));
880+
// regular element
881+
fixture.detectChanges();
879882
fixture.detectChanges();
880883
expect(cmp.numberOfChecks).toEqual(2);
884+
// element inside of an *ngIf
885+
cmpEl.children[1].triggerEventHandler("click", ({} as dynamic));
886+
fixture.detectChanges();
887+
fixture.detectChanges();
888+
expect(cmp.numberOfChecks).toEqual(3);
889+
// element inside a nested component
890+
cmpEl.children[2].children[0]
891+
.triggerEventHandler("click", ({} as dynamic));
892+
fixture.detectChanges();
893+
fixture.detectChanges();
894+
expect(cmp.numberOfChecks).toEqual(4);
881895
async.done();
882896
});
883897
}));
@@ -2139,18 +2153,26 @@ class DirectiveWithTitleAndHostProperty {
21392153
String title;
21402154
}
21412155

2156+
@Component(selector: "event-cmp", template: "<div (click)=\"noop()\"></div>")
2157+
class EventCmp {
2158+
noop() {}
2159+
}
2160+
21422161
@Component(
21432162
selector: "push-cmp",
21442163
inputs: const ["prop"],
21452164
changeDetection: ChangeDetectionStrategy.OnPush,
2146-
template: "{{field}}")
2165+
template:
2166+
"{{field}}<div (click)=\"noop()\"></div><div *ngIf=\"true\" (click)=\"noop()\"></div><event-cmp></event-cmp>",
2167+
directives: const [EventCmp, NgIf])
21472168
@Injectable()
21482169
class PushCmp {
21492170
num numberOfChecks;
21502171
var prop;
21512172
PushCmp() {
21522173
this.numberOfChecks = 0;
21532174
}
2175+
noop() {}
21542176
get field {
21552177
this.numberOfChecks++;
21562178
return "fixed";

0 commit comments

Comments
 (0)