From 6dbfe0dc2e302ed8e742d9beed3cbb6b4f014de5 Mon Sep 17 00:00:00 2001 From: Jeremy Elbourn Date: Fri, 6 Feb 2015 12:17:34 -0800 Subject: [PATCH] feat(vars): assignment of component or element instance to vars. --- .../src/core/compiler/element_injector.js | 32 +++++++++++ .../core/compiler/pipeline/compile_element.js | 10 +++- .../pipeline/property_binding_parser.js | 25 ++++++--- .../proto_element_injector_builder.js | 19 ++++++- .../compiler/pipeline/proto_view_builder.js | 15 +++++ modules/angular2/src/core/compiler/view.js | 10 ++++ .../test/core/compiler/integration_spec.js | 56 +++++++++++++++++++ .../pipeline/property_binding_parser_spec.js | 22 ++++++-- .../proto_element_injector_builder_spec.js | 39 ++++++++++++- .../pipeline/proto_view_builder_spec.js | 17 +++++- 10 files changed, 224 insertions(+), 21 deletions(-) diff --git a/modules/angular2/src/core/compiler/element_injector.js b/modules/angular2/src/core/compiler/element_injector.js index b154e5148e..d32980294e 100644 --- a/modules/angular2/src/core/compiler/element_injector.js +++ b/modules/angular2/src/core/compiler/element_injector.js @@ -211,10 +211,22 @@ export class ProtoElementInjector { index:int; view:View; distanceToParent:number; + + /** Whether the element is exported as $implicit. */ + exportElement:boolean; + + /** Whether the component instance is exported as $implicit. */ + exportComponent:boolean; + + /** The variable name that will be set to $implicit for the element. */ + exportImplicitName:string; + constructor(parent:ProtoElementInjector, index:int, bindings:List, firstBindingIsComponent:boolean = false, distanceToParent:number = 0) { this.parent = parent; this.index = index; this.distanceToParent = distanceToParent; + this.exportComponent = false; + this.exportElement = false; this._binding0IsComponent = firstBindingIsComponent; this._binding0 = null; this._keyId0 = null; @@ -405,6 +417,11 @@ export class ElementInjector extends TreeNode { return this._preBuiltObjects.element.domElement === el; } + /** Gets the NgElement associated with this ElementInjector */ + getNgElement() { + return this._preBuiltObjects.element; + } + getComponent() { if (this._proto._binding0IsComponent) { return this._obj0; @@ -603,6 +620,21 @@ export class ElementInjector extends TreeNode { hasEventEmitter(eventName: string) { return this._proto.hasEventEmitter(eventName); } + + /** Gets whether this element is exporting a component instance as $implicit. */ + isExportingComponent() { + return this._proto.exportComponent; + } + + /** Gets whether this element is exporting its element as $implicit. */ + isExportingElement() { + return this._proto.exportElement; + } + + /** Get the name to which this element's $implicit is to be assigned. */ + getExportImplicitName() { + return this._proto.exportImplicitName; + } } class OutOfBoundsAccess extends Error { diff --git a/modules/angular2/src/core/compiler/pipeline/compile_element.js b/modules/angular2/src/core/compiler/pipeline/compile_element.js index 597ca1e05a..c8d6352c2b 100644 --- a/modules/angular2/src/core/compiler/pipeline/compile_element.js +++ b/modules/angular2/src/core/compiler/pipeline/compile_element.js @@ -106,11 +106,17 @@ export class CompileElement { MapWrapper.set(this.propertyBindings, property, expression); } - addVariableBinding(directiveName:string, templateName:string) { + addVariableBinding(variableName:string, variableValue:string) { if (isBlank(this.variableBindings)) { this.variableBindings = MapWrapper.create(); } - MapWrapper.set(this.variableBindings, templateName, directiveName); + + // Store the variable map from value to variable, reflecting how it will be used later by + // View. When a local is set to the view, a lookup for the variable name will take place keyed + // by the "value", or exported identifier. For example, ng-repeat sets a view local of "index". + // When this occurs, a lookup keyed by "index" must occur to find if there is a var referencing + // it. + MapWrapper.set(this.variableBindings, variableValue, variableName); } addEventBinding(eventName:string, expression:AST) { diff --git a/modules/angular2/src/core/compiler/pipeline/property_binding_parser.js b/modules/angular2/src/core/compiler/pipeline/property_binding_parser.js index d6103944c0..07063ff6ae 100644 --- a/modules/angular2/src/core/compiler/pipeline/property_binding_parser.js +++ b/modules/angular2/src/core/compiler/pipeline/property_binding_parser.js @@ -9,7 +9,16 @@ import {CompileElement} from './compile_element'; import {CompileControl} from './compile_control'; // TODO(tbosch): Cannot make this const/final right now because of the transpiler... -var BIND_NAME_REGEXP = RegExpWrapper.create('^(?:(?:(bind)|(var)|(on))-(.+))|\\[([^\\]]+)\\]|\\(([^\\)]+)\\)'); +// Group 1 = "bind" +// Group 2 = "var" +// Group 3 = "on" +// Group 4 = the identifier after "bind", "var", or "on" +// Group 5 = idenitifer inside square braces +// Group 6 = identifier inside parenthesis +// Group 7 = "#" +// Group 8 = identifier after "#" +var BIND_NAME_REGEXP = RegExpWrapper.create( + '^(?:(?:(bind)|(var)|(on))-(.+))|\\[([^\\]]+)\\]|\\(([^\\)]+)\\)|(#)(.+)'); /** * Parses the property bindings on a single element. @@ -35,14 +44,12 @@ export class PropertyBindingParser extends CompileStep { if (isPresent(bindParts[1])) { // match: bind-prop current.addPropertyBinding(bindParts[4], this._parseBinding(attrValue)); - } else if (isPresent(bindParts[2])) { - // match: let-prop - // Note: We assume that the ViewSplitter already did its work, i.e. template directive should - // only be present on