refactor(render): cleanup access to native dom elements

BREAKING CHANGES:
- rename `ElementRef.domElement` to `ElementRef.nativeElement`
- add `Renderer.getNativeElementSync` to make the app side
  less dependent on the dom renderer.
- don’t use `ElementRef.nativeElement` in directives but
  use the methods on `Renderer` directly.
- Removed `ElementRef.setAttribute`. Use `Renderer.setElementAttribute` instead.

Closes #2712
Last part of #2476
Closes #2476
This commit is contained in:
Tobias Bosch 2015-06-23 14:26:02 -07:00
parent 5c9e53a25e
commit c8bdacb195
24 changed files with 115 additions and 134 deletions

View File

@ -1,2 +1,2 @@
export * from './src/debug/debug_element'; export * from './src/debug/debug_element';
export {inspectDomElement, ELEMENT_PROBE_CONFIG} from './src/debug/debug_element_view_listener'; export {inspectNativeElement, ELEMENT_PROBE_CONFIG} from './src/debug/debug_element_view_listener';

View File

@ -56,7 +56,6 @@ import {AppViewListener} from 'angular2/src/core/compiler/view_listener';
import {ProtoViewFactory} from 'angular2/src/core/compiler/proto_view_factory'; import {ProtoViewFactory} from 'angular2/src/core/compiler/proto_view_factory';
import {Renderer, RenderCompiler} from 'angular2/src/render/api'; import {Renderer, RenderCompiler} from 'angular2/src/render/api';
import {DomRenderer, DOCUMENT_TOKEN} from 'angular2/src/render/dom/dom_renderer'; import {DomRenderer, DOCUMENT_TOKEN} from 'angular2/src/render/dom/dom_renderer';
import {resolveInternalDomView} from 'angular2/src/render/dom/view/view';
import {DefaultDomCompiler} from 'angular2/src/render/dom/compiler/compiler'; import {DefaultDomCompiler} from 'angular2/src/render/dom/compiler/compiler';
import {internalView} from 'angular2/src/core/compiler/view_ref'; import {internalView} from 'angular2/src/core/compiler/view_ref';
@ -85,10 +84,7 @@ function _injectorBindings(appComponentType): List<Type | Binding | List<any>> {
// TODO(rado): investigate whether to support bindings on root component. // TODO(rado): investigate whether to support bindings on root component.
return dynamicComponentLoader.loadAsRoot(appComponentType, null, injector) return dynamicComponentLoader.loadAsRoot(appComponentType, null, injector)
.then((componentRef) => { .then((componentRef) => {
var domView = resolveInternalDomView(componentRef.hostView.render); registry.registerApplication(componentRef.location.nativeElement, testability);
// We need to do this here to ensure that we create Testability and
// it's ready on the window for users.
registry.registerApplication(domView.boundElements[0].element, testability);
return componentRef; return componentRef;
}); });

View File

@ -36,7 +36,7 @@ export class DynamicComponentLoader {
.then(hostProtoViewRef => { .then(hostProtoViewRef => {
var hostViewRef = var hostViewRef =
this._viewManager.createRootHostView(hostProtoViewRef, overrideSelector, injector); this._viewManager.createRootHostView(hostProtoViewRef, overrideSelector, injector);
var newLocation = new ElementRef(hostViewRef, 0); var newLocation = this._viewManager.getHostElement(hostViewRef);
var component = this._viewManager.getComponent(newLocation); var component = this._viewManager.getComponent(newLocation);
var dispose = () => { this._viewManager.destroyRootHostView(hostViewRef); }; var dispose = () => { this._viewManager.destroyRootHostView(hostViewRef); };
@ -68,7 +68,7 @@ export class DynamicComponentLoader {
var viewContainer = this._viewManager.getViewContainer(location); var viewContainer = this._viewManager.getViewContainer(location);
var hostViewRef = var hostViewRef =
viewContainer.create(hostProtoViewRef, viewContainer.length, null, injector); viewContainer.create(hostProtoViewRef, viewContainer.length, null, injector);
var newLocation = new ElementRef(hostViewRef, 0); var newLocation = this._viewManager.getHostElement(hostViewRef);
var component = this._viewManager.getComponent(newLocation); var component = this._viewManager.getComponent(newLocation);
var dispose = () => { var dispose = () => {

View File

@ -1,41 +1,22 @@
import {DOM} from 'angular2/src/dom/dom_adapter'; import {BaseException} from 'angular2/src/facade/lang';
import {normalizeBlank, BaseException} from 'angular2/src/facade/lang';
import {ViewRef} from './view_ref'; import {ViewRef} from './view_ref';
import {resolveInternalDomView} from 'angular2/src/render/dom/view/view'; import {RenderViewRef, RenderElementRef, Renderer} from 'angular2/src/render/api';
import {RenderViewRef, RenderElementRef} from 'angular2/src/render/api';
/** /**
* @exportedAs angular2/view * @exportedAs angular2/view
*/ */
export class ElementRef implements RenderElementRef { export class ElementRef implements RenderElementRef {
constructor(public parentView: ViewRef, public boundElementIndex: number) {} constructor(public parentView: ViewRef, public boundElementIndex: number,
private _renderer: Renderer) {}
get renderView() { return this.parentView.render; } get renderView(): RenderViewRef { return this.parentView.render; }
// TODO(tbosch): remove this once Typescript supports declaring interfaces // TODO(tbosch): remove this once Typescript supports declaring interfaces
// that contain getters // that contain getters
set renderView(value: any) { throw new BaseException('Abstract setter'); } set renderView(viewRef: RenderViewRef) { throw new BaseException('Abstract setter'); }
/** /**
* Exposes the underlying DOM element. * Exposes the underlying native element.
* (DEPRECATED way of accessing the DOM, replacement coming) * Attention: This won't work in a webworker scenario!
*/ */
// TODO(tbosch): Here we expose the real DOM element. get nativeElement(): any { return this._renderer.getNativeElementSync(this); }
// We need a more general way to read/write to the DOM element
// via a proper abstraction in the render layer
get domElement() {
return resolveInternalDomView(this.parentView.render)
.boundElements[this.boundElementIndex]
.element;
}
/**
* Gets an attribute from the underlying DOM element.
* (DEPRECATED way of accessing the DOM, replacement coming)
*/
// TODO(tbosch): Here we expose the real DOM element.
// We need a more general way to read/write to the DOM element
// via a proper abstraction in the render layer
getAttribute(name: string): string {
return normalizeBlank(DOM.getAttribute(this.domElement, name));
}
} }

View File

@ -65,7 +65,7 @@ export class AppView implements ChangeDispatcher, EventDispatcher {
this.elementRefs = ListWrapper.createFixedSize(this.proto.elementBinders.length); this.elementRefs = ListWrapper.createFixedSize(this.proto.elementBinders.length);
this.ref = new ViewRef(this); this.ref = new ViewRef(this);
for (var i = 0; i < this.elementRefs.length; i++) { for (var i = 0; i < this.elementRefs.length; i++) {
this.elementRefs[i] = new ElementRef(this.ref, i); this.elementRefs[i] = new ElementRef(this.ref, i, renderer);
} }
this.locals = new Locals(null, MapWrapper.clone(protoLocals)); // TODO optimize this this.locals = new Locals(null, MapWrapper.clone(protoLocals)); // TODO optimize this
} }

View File

@ -30,6 +30,10 @@ export class AppViewManager {
return hostView.elementInjectors[location.boundElementIndex].getViewContainerRef(); return hostView.elementInjectors[location.boundElementIndex].getViewContainerRef();
} }
getHostElement(hostViewRef: ViewRef): ElementRef {
return internalView(hostViewRef).elementRefs[0];
}
/** /**
* Returns an ElementRef for the element with the given variable name * Returns an ElementRef for the element with the given variable name
* in the component view of the component at the provided ElementRef. * in the component view of the component at the provided ElementRef.

View File

@ -165,7 +165,7 @@ export class AppViewManagerUtils {
if (isPresent(elementInjector.getDirectiveVariableBindings())) { if (isPresent(elementInjector.getDirectiveVariableBindings())) {
MapWrapper.forEach(elementInjector.getDirectiveVariableBindings(), (directiveIndex, name) => { MapWrapper.forEach(elementInjector.getDirectiveVariableBindings(), (directiveIndex, name) => {
if (isBlank(directiveIndex)) { if (isBlank(directiveIndex)) {
view.locals.set(name, elementInjector.getElementRef().domElement); view.locals.set(name, elementInjector.getElementRef().nativeElement);
} else { } else {
view.locals.set(name, elementInjector.getDirectiveAtIndex(directiveIndex)); view.locals.set(name, elementInjector.getDirectiveAtIndex(directiveIndex));
} }

View File

@ -8,8 +8,6 @@ import {AppView} from 'angular2/src/core/compiler/view';
import {internalView} from 'angular2/src/core/compiler/view_ref'; import {internalView} from 'angular2/src/core/compiler/view_ref';
import {ElementRef} from 'angular2/src/core/compiler/element_ref'; import {ElementRef} from 'angular2/src/core/compiler/element_ref';
import {resolveInternalDomView} from 'angular2/src/render/dom/view/view';
/** /**
* @exportedAs angular2/test * @exportedAs angular2/test
* *
@ -35,13 +33,9 @@ export class DebugElement {
return this._elementInjector.getComponent(); return this._elementInjector.getComponent();
} }
get domElement(): any { get nativeElement(): any { return this.elementRef.nativeElement; }
return resolveInternalDomView(this._parentView.render)
.boundElements[this._boundElementIndex]
.element;
}
get elementRef(): ElementRef { return this._elementInjector.getElementRef(); } get elementRef(): ElementRef { return this._parentView.elementRefs[this._boundElementIndex]; }
getDirectiveInstance(directiveIndex: number): any { getDirectiveInstance(directiveIndex: number): any {
return this._elementInjector.getDirectiveAtIndex(directiveIndex); return this._elementInjector.getDirectiveAtIndex(directiveIndex);
@ -192,7 +186,7 @@ export class By {
static all(): Function { return (debugElement) => true; } static all(): Function { return (debugElement) => true; }
static css(selector: string): Function { static css(selector: string): Function {
return (debugElement) => { return DOM.elementMatches(debugElement.domElement, selector); }; return (debugElement) => { return DOM.elementMatches(debugElement.nativeElement, selector); };
} }
static directive(type: Type): Function { static directive(type: Type): Function {
return (debugElement) => { return debugElement.hasDirective(type); }; return (debugElement) => { return debugElement.hasDirective(type); };

View File

@ -10,7 +10,7 @@ import {Injectable, bind, Binding} from 'angular2/di';
import {AppViewListener} from 'angular2/src/core/compiler/view_listener'; import {AppViewListener} from 'angular2/src/core/compiler/view_listener';
import {AppView} from 'angular2/src/core/compiler/view'; import {AppView} from 'angular2/src/core/compiler/view';
import {DOM} from 'angular2/src/dom/dom_adapter'; import {DOM} from 'angular2/src/dom/dom_adapter';
import {resolveInternalDomView} from 'angular2/src/render/dom/view/view'; import {Renderer} from 'angular2/src/render/api';
import {DebugElement} from './debug_element'; import {DebugElement} from './debug_element';
const NG_ID_PROPERTY = 'ngid'; const NG_ID_PROPERTY = 'ngid';
@ -41,7 +41,7 @@ function _getElementId(element): List<number> {
} }
} }
export function inspectDomElement(element): DebugElement { export function inspectNativeElement(element): DebugElement {
var elId = _getElementId(element); var elId = _getElementId(element);
if (isPresent(elId)) { if (isPresent(elId)) {
var view = _allViewsById.get(elId[0]); var view = _allViewsById.get(elId[0]);
@ -54,15 +54,16 @@ export function inspectDomElement(element): DebugElement {
@Injectable() @Injectable()
export class DebugElementViewListener implements AppViewListener { export class DebugElementViewListener implements AppViewListener {
constructor() { DOM.setGlobalVar(INSPECT_GLOBAL_NAME, inspectDomElement); } constructor(private _renderer: Renderer) {
DOM.setGlobalVar(INSPECT_GLOBAL_NAME, inspectNativeElement);
}
viewCreated(view: AppView) { viewCreated(view: AppView) {
var viewId = _nextId++; var viewId = _nextId++;
_allViewsById.set(viewId, view); _allViewsById.set(viewId, view);
_allIdsByView.set(view, viewId); _allIdsByView.set(view, viewId);
var renderView = resolveInternalDomView(view.render); for (var i = 0; i < view.elementRefs.length; i++) {
for (var i = 0; i < renderView.boundElements.length; i++) { _setElementId(this._renderer.getNativeElementSync(view.elementRefs[i]), [viewId, i]);
_setElementId(renderView.boundElements[i].element, [viewId, i]);
} }
} }

View File

@ -2,17 +2,15 @@ import {Directive, onCheck} from 'angular2/annotations';
import {ElementRef} from 'angular2/core'; import {ElementRef} from 'angular2/core';
import {PipeRegistry} from 'angular2/src/change_detection/pipes/pipe_registry'; import {PipeRegistry} from 'angular2/src/change_detection/pipes/pipe_registry';
import {isPresent} from 'angular2/src/facade/lang'; import {isPresent} from 'angular2/src/facade/lang';
import {DOM} from 'angular2/src/dom/dom_adapter'; import {Renderer} from 'angular2/src/render/api';
@Directive({selector: '[class]', lifecycle: [onCheck], properties: ['rawClass: class']}) @Directive({selector: '[class]', lifecycle: [onCheck], properties: ['rawClass: class']})
export class CSSClass { export class CSSClass {
_domEl;
_pipe; _pipe;
_rawClass; _rawClass;
constructor(private _pipeRegistry: PipeRegistry, ngEl: ElementRef) { constructor(private _pipeRegistry: PipeRegistry, private _ngEl: ElementRef,
this._domEl = ngEl.domElement; private _renderer: Renderer) {}
}
set rawClass(v) { set rawClass(v) {
this._rawClass = v; this._rawClass = v;
@ -20,11 +18,7 @@ export class CSSClass {
} }
_toggleClass(className, enabled): void { _toggleClass(className, enabled): void {
if (enabled) { this._renderer.setElementClass(this._ngEl, className, enabled);
DOM.addClass(this._domEl, className);
} else {
DOM.removeClass(this._domEl, className);
}
} }
onCheck() { onCheck() {
@ -38,7 +32,7 @@ export class CSSClass {
diff.forEachChangedItem((record) => { this._toggleClass(record.key, record.currentValue); }); diff.forEachChangedItem((record) => { this._toggleClass(record.key, record.currentValue); });
diff.forEachRemovedItem((record) => { diff.forEachRemovedItem((record) => {
if (record.previousValue) { if (record.previousValue) {
DOM.removeClass(this._domEl, record.key); this._toggleClass(record.key, false);
} }
}); });
} }

View File

@ -370,6 +370,12 @@ export class Renderer {
*/ */
dehydrateView(viewRef: RenderViewRef) {} dehydrateView(viewRef: RenderViewRef) {}
/**
* Returns the native element at the given location.
* Attention: In a WebWorker scenario, this should always return null!
*/
getNativeElementSync(location: RenderElementRef): any { return null; }
/** /**
* Sets a property on an element. * Sets a property on an element.
*/ */

View File

@ -53,6 +53,12 @@ export class DomRenderer extends Renderer {
// noop for now // noop for now
} }
getNativeElementSync(location: RenderElementRef) {
return resolveInternalDomView(location.renderView)
.boundElements[location.boundElementIndex]
.element;
}
attachComponentView(location: RenderElementRef, componentViewRef: RenderViewRef) { attachComponentView(location: RenderElementRef, componentViewRef: RenderViewRef) {
var hostView = resolveInternalDomView(location.renderView); var hostView = resolveInternalDomView(location.renderView);
var componentView = resolveInternalDomView(componentViewRef); var componentView = resolveInternalDomView(componentViewRef);

View File

@ -4,10 +4,10 @@ import {ElementRef} from 'angular2/core';
import {StringMap, StringMapWrapper} from 'angular2/src/facade/collection'; import {StringMap, StringMapWrapper} from 'angular2/src/facade/collection';
import {isPresent} from 'angular2/src/facade/lang'; import {isPresent} from 'angular2/src/facade/lang';
import {DOM} from 'angular2/src/dom/dom_adapter';
import {Router} from './router'; import {Router} from './router';
import {Location} from './location'; import {Location} from './location';
import {Renderer} from 'angular2/src/render/api';
/** /**
* The RouterLink directive lets you link to specific parts of your app. * The RouterLink directive lets you link to specific parts of your app.
@ -37,7 +37,6 @@ import {Location} from './location';
host: {'(^click)': 'onClick()'} host: {'(^click)': 'onClick()'}
}) })
export class RouterLink { export class RouterLink {
private _domEl;
private _route: string; private _route: string;
private _params: StringMap<string, string>; private _params: StringMap<string, string>;
@ -46,8 +45,8 @@ export class RouterLink {
// the url passed to the router navigation. // the url passed to the router navigation.
_navigationHref: string; _navigationHref: string;
constructor(elementRef: ElementRef, private _router: Router, private _location: Location) { constructor(private _elementRef: ElementRef, private _router: Router, private _location: Location,
this._domEl = elementRef.domElement; private _renderer: Renderer) {
this._params = StringMapWrapper.create(); this._params = StringMapWrapper.create();
} }
@ -66,7 +65,7 @@ export class RouterLink {
this._visibleHref = this._location.normalizeAbsolutely(this._navigationHref); this._visibleHref = this._location.normalizeAbsolutely(this._navigationHref);
// Keeping the link on the element to support contextual menu `copy link` // Keeping the link on the element to support contextual menu `copy link`
// and other in-browser affordances. // and other in-browser affordances.
DOM.setAttribute(this._domEl, 'href', this._visibleHref); this._renderer.setElementAttribute(this._elementRef, 'href', this._visibleHref);
} }
} }
} }

View File

@ -24,7 +24,7 @@ export class Ruler {
constructor(domAdapter: DomAdapter) { this.domAdapter = domAdapter; } constructor(domAdapter: DomAdapter) { this.domAdapter = domAdapter; }
measure(el: ElementRef): Promise<Rectangle> { measure(el: ElementRef): Promise<Rectangle> {
var clntRect = <any>this.domAdapter.getBoundingClientRect(el.domElement); var clntRect = <any>this.domAdapter.getBoundingClientRect(el.nativeElement);
// even if getBoundingClientRect is synchronous we use async API in preparation for further // even if getBoundingClientRect is synchronous we use async API in preparation for further
// changes // changes

View File

@ -41,7 +41,7 @@ export function main() {
loader.loadIntoLocation(DynamicallyLoaded, tc.elementRef, 'loc') loader.loadIntoLocation(DynamicallyLoaded, tc.elementRef, 'loc')
.then(ref => { .then(ref => {
expect(tc.domElement).toHaveText("Location;DynamicallyLoaded;"); expect(tc.nativeElement).toHaveText("Location;DynamicallyLoaded;");
async.done(); async.done();
}); });
}); });
@ -60,7 +60,7 @@ export function main() {
loader.loadIntoLocation(DynamicallyLoaded, tc.elementRef, 'loc') loader.loadIntoLocation(DynamicallyLoaded, tc.elementRef, 'loc')
.then(ref => { .then(ref => {
ref.dispose(); ref.dispose();
expect(tc.domElement).toHaveText("Location;"); expect(tc.nativeElement).toHaveText("Location;");
async.done(); async.done();
}); });
}); });
@ -81,7 +81,7 @@ export function main() {
tc.detectChanges(); tc.detectChanges();
var newlyInsertedElement = DOM.childNodes(tc.domElement)[1]; var newlyInsertedElement = DOM.childNodes(tc.nativeElement)[1];
expect(newlyInsertedElement.id) expect(newlyInsertedElement.id)
.toEqual("new value") .toEqual("new value")

View File

@ -256,8 +256,8 @@ export function main() {
view.detectChanges(); view.detectChanges();
expect(q.query.first.domElement).toHaveText("1d"); expect(q.query.first.nativeElement).toHaveText("1d");
expect(q.query.last.domElement).toHaveText("2d"); expect(q.query.last.nativeElement).toHaveText("2d");
async.done(); async.done();
}); });

View File

@ -16,14 +16,12 @@ import {
proxy proxy
} from 'angular2/test_lib'; } from 'angular2/test_lib';
import {MapWrapper} from 'angular2/src/facade/collection';
import {IMPLEMENTS} from 'angular2/src/facade/lang'; import {IMPLEMENTS} from 'angular2/src/facade/lang';
import {AppView, AppProtoView, AppViewContainer} from 'angular2/src/core/compiler/view'; import {AppView, AppProtoView, AppViewContainer} from 'angular2/src/core/compiler/view';
import {ProtoViewRef, ViewRef, internalView} from 'angular2/src/core/compiler/view_ref';
import {ElementRef} from 'angular2/src/core/compiler/element_ref';
import {ViewContainerRef} from 'angular2/src/core/compiler/view_container_ref'; import {ViewContainerRef} from 'angular2/src/core/compiler/view_container_ref';
import {AppViewManager} from 'angular2/src/core/compiler/view_manager'; import {AppViewManager} from 'angular2/src/core/compiler/view_manager';
import {ElementBinder} from 'angular2/src/core/compiler/element_binder';
export function main() { export function main() {
// TODO(tbosch): add missing tests // TODO(tbosch): add missing tests
@ -33,9 +31,11 @@ export function main() {
var view; var view;
var viewManager; var viewManager;
function wrapView(view: AppView): ViewRef { return new ViewRef(view); } function createProtoView() {
var pv = new AppProtoView(null, null, null, null);
function createProtoView() { return new AppProtoView(null, null, null, null); } pv.elementBinders = [new ElementBinder(0, null, 0, null, null)];
return pv;
}
function createView() { return new AppView(null, createProtoView(), new Map()); } function createView() { return new AppView(null, createProtoView(), new Map()); }
@ -45,7 +45,7 @@ export function main() {
viewManager = new AppViewManagerSpy(); viewManager = new AppViewManagerSpy();
view = createView(); view = createView();
view.viewContainers = [null]; view.viewContainers = [null];
location = new ElementRef(wrapView(view), 0); location = view.elementRefs[0];
}); });
describe('length', () => { describe('length', () => {

View File

@ -21,7 +21,6 @@ import {MapWrapper, ListWrapper, StringMapWrapper} from 'angular2/src/facade/col
import {AppProtoView, AppView, AppViewContainer} from 'angular2/src/core/compiler/view'; import {AppProtoView, AppView, AppViewContainer} from 'angular2/src/core/compiler/view';
import {ProtoViewRef, ViewRef, internalView} from 'angular2/src/core/compiler/view_ref'; import {ProtoViewRef, ViewRef, internalView} from 'angular2/src/core/compiler/view_ref';
import {ElementRef} from 'angular2/src/core/compiler/element_ref';
import {Renderer, RenderViewRef, RenderProtoViewRef} from 'angular2/src/render/api'; import {Renderer, RenderViewRef, RenderProtoViewRef} from 'angular2/src/render/api';
import {ElementBinder} from 'angular2/src/core/compiler/element_binder'; import {ElementBinder} from 'angular2/src/core/compiler/element_binder';
import {DirectiveBinding, ElementInjector} from 'angular2/src/core/compiler/element_injector'; import {DirectiveBinding, ElementInjector} from 'angular2/src/core/compiler/element_injector';
@ -50,7 +49,7 @@ export function main() {
function wrapView(view: AppView): ViewRef { return new ViewRef(view); } function wrapView(view: AppView): ViewRef { return new ViewRef(view); }
function elementRef(parentView, boundElementIndex) { function elementRef(parentView, boundElementIndex) {
return new ElementRef(parentView, boundElementIndex); return parentView.elementRefs[boundElementIndex];
} }
function createDirectiveBinding(type) { function createDirectiveBinding(type) {
@ -277,13 +276,12 @@ export function main() {
}); });
it('should create a ViewContainerRef if not yet existing', () => { it('should create a ViewContainerRef if not yet existing', () => {
manager.createViewInContainer(elementRef(wrapView(parentView), 0), 0, manager.createViewInContainer(elementRef(parentView, 0), 0, wrapPv(childProtoView), null);
wrapPv(childProtoView), null);
expect(parentView.viewContainers[0]).toBeTruthy(); expect(parentView.viewContainers[0]).toBeTruthy();
}); });
it('should create the view', () => { it('should create the view', () => {
expect(internalView(manager.createViewInContainer(elementRef(wrapView(parentView), 0), 0, expect(internalView(manager.createViewInContainer(elementRef(parentView, 0), 0,
wrapPv(childProtoView), null))) wrapPv(childProtoView), null)))
.toBe(createdViews[0]); .toBe(createdViews[0]);
expect(createdViews[0].proto).toBe(childProtoView); expect(createdViews[0].proto).toBe(childProtoView);
@ -291,10 +289,11 @@ export function main() {
}); });
it('should attach the view', () => { it('should attach the view', () => {
var contextView = createView(); var contextView =
var elRef = elementRef(wrapView(parentView), 0); createView(createProtoView([createEmptyElBinder(), createEmptyElBinder()]));
var elRef = elementRef(parentView, 0);
manager.createViewInContainer(elRef, 0, wrapPv(childProtoView), manager.createViewInContainer(elRef, 0, wrapPv(childProtoView),
elementRef(wrapView(contextView), 1), null); elementRef(contextView, 1), null);
expect(utils.spy('attachViewInContainer')) expect(utils.spy('attachViewInContainer'))
.toHaveBeenCalledWith(parentView, 0, contextView, 1, 0, createdViews[0]); .toHaveBeenCalledWith(parentView, 0, contextView, 1, 0, createdViews[0]);
expect(renderer.spy('attachViewInContainer')) expect(renderer.spy('attachViewInContainer'))
@ -303,25 +302,25 @@ export function main() {
it('should hydrate the view', () => { it('should hydrate the view', () => {
var injector = new Injector([], null, false); var injector = new Injector([], null, false);
var contextView = createView(); var contextView =
manager.createViewInContainer(elementRef(wrapView(parentView), 0), 0, createView(createProtoView([createEmptyElBinder(), createEmptyElBinder()]));
wrapPv(childProtoView), manager.createViewInContainer(elementRef(parentView, 0), 0, wrapPv(childProtoView),
elementRef(wrapView(contextView), 1), injector); elementRef(contextView, 1), injector);
expect(utils.spy('hydrateViewInContainer')) expect(utils.spy('hydrateViewInContainer'))
.toHaveBeenCalledWith(parentView, 0, contextView, 1, 0, injector); .toHaveBeenCalledWith(parentView, 0, contextView, 1, 0, injector);
expect(renderer.spy('hydrateView')).toHaveBeenCalledWith(createdViews[0].render); expect(renderer.spy('hydrateView')).toHaveBeenCalledWith(createdViews[0].render);
}); });
it('should create and set the render view', () => { it('should create and set the render view', () => {
manager.createViewInContainer(elementRef(wrapView(parentView), 0), 0, manager.createViewInContainer(elementRef(parentView, 0), 0, wrapPv(childProtoView), null,
wrapPv(childProtoView), null, null); null);
expect(renderer.spy('createView')).toHaveBeenCalledWith(childProtoView.render); expect(renderer.spy('createView')).toHaveBeenCalledWith(childProtoView.render);
expect(createdViews[0].render).toBe(createdRenderViews[0]); expect(createdViews[0].render).toBe(createdRenderViews[0]);
}); });
it('should set the event dispatcher', () => { it('should set the event dispatcher', () => {
manager.createViewInContainer(elementRef(wrapView(parentView), 0), 0, manager.createViewInContainer(elementRef(parentView, 0), 0, wrapPv(childProtoView), null,
wrapPv(childProtoView), null, null); null);
var childView = createdViews[0]; var childView = createdViews[0];
expect(renderer.spy('setEventDispatcher')) expect(renderer.spy('setEventDispatcher'))
.toHaveBeenCalledWith(childView.render, childView); .toHaveBeenCalledWith(childView.render, childView);
@ -337,19 +336,19 @@ export function main() {
beforeEach(() => { beforeEach(() => {
parentView = createView(createProtoView([createEmptyElBinder()])); parentView = createView(createProtoView([createEmptyElBinder()]));
childProtoView = createProtoView(); childProtoView = createProtoView();
childView = internalView(manager.createViewInContainer( childView = internalView(manager.createViewInContainer(elementRef(parentView, 0), 0,
elementRef(wrapView(parentView), 0), 0, wrapPv(childProtoView), null)); wrapPv(childProtoView), null));
}); });
it('should dehydrate', () => { it('should dehydrate', () => {
manager.destroyViewInContainer(elementRef(wrapView(parentView), 0), 0); manager.destroyViewInContainer(elementRef(parentView, 0), 0);
expect(utils.spy('dehydrateView')) expect(utils.spy('dehydrateView'))
.toHaveBeenCalledWith(parentView.viewContainers[0].views[0]); .toHaveBeenCalledWith(parentView.viewContainers[0].views[0]);
expect(renderer.spy('dehydrateView')).toHaveBeenCalledWith(childView.render); expect(renderer.spy('dehydrateView')).toHaveBeenCalledWith(childView.render);
}); });
it('should detach', () => { it('should detach', () => {
var elRef = elementRef(wrapView(parentView), 0); var elRef = elementRef(parentView, 0);
manager.destroyViewInContainer(elRef, 0); manager.destroyViewInContainer(elRef, 0);
expect(utils.spy('detachViewInContainer')).toHaveBeenCalledWith(parentView, 0, 0); expect(utils.spy('detachViewInContainer')).toHaveBeenCalledWith(parentView, 0, 0);
expect(renderer.spy('detachViewInContainer')) expect(renderer.spy('detachViewInContainer'))
@ -357,7 +356,7 @@ export function main() {
}); });
it('should return the view to the pool', () => { it('should return the view to the pool', () => {
manager.destroyViewInContainer(elementRef(wrapView(parentView), 0), 0); manager.destroyViewInContainer(elementRef(parentView, 0), 0);
expect(viewPool.spy('returnView')).toHaveBeenCalledWith(childView); expect(viewPool.spy('returnView')).toHaveBeenCalledWith(childView);
}); });
}); });
@ -367,8 +366,8 @@ export function main() {
beforeEach(() => { beforeEach(() => {
parentView = createView(createProtoView([createEmptyElBinder()])); parentView = createView(createProtoView([createEmptyElBinder()]));
childProtoView = createProtoView(); childProtoView = createProtoView();
childView = internalView(manager.createViewInContainer( childView = internalView(manager.createViewInContainer(elementRef(parentView, 0), 0,
elementRef(wrapView(parentView), 0), 0, wrapPv(childProtoView), null)); wrapPv(childProtoView), null));
}); });
it('should dehydrate', () => { it('should dehydrate', () => {

View File

@ -142,25 +142,26 @@ export function main() {
var rootCompChildren = rootTestComponent.componentViewChildren; var rootCompChildren = rootTestComponent.componentViewChildren;
// The root component has 3 elements in its shadow view. // The root component has 3 elements in its shadow view.
expect(rootCompChildren.length).toEqual(3); expect(rootCompChildren.length).toEqual(3);
expect(DOM.hasClass(rootCompChildren[0].domElement, 'parent')).toBe(true); expect(DOM.hasClass(rootCompChildren[0].nativeElement, 'parent')).toBe(true);
expect(DOM.hasClass(rootCompChildren[1].domElement, 'parent')).toBe(true); expect(DOM.hasClass(rootCompChildren[1].nativeElement, 'parent')).toBe(true);
expect(DOM.hasClass(rootCompChildren[2].domElement, 'child-comp-class')).toBe(true); expect(DOM.hasClass(rootCompChildren[2].nativeElement, 'child-comp-class'))
.toBe(true);
var nested = rootCompChildren[0].children; var nested = rootCompChildren[0].children;
expect(nested.length).toEqual(1); expect(nested.length).toEqual(1);
expect(DOM.hasClass(nested[0].domElement, 'parentnested')).toBe(true); expect(DOM.hasClass(nested[0].nativeElement, 'parentnested')).toBe(true);
var childComponent = rootCompChildren[2]; var childComponent = rootCompChildren[2];
expect(childComponent.children.length).toEqual(0); expect(childComponent.children.length).toEqual(0);
var childCompChildren = childComponent.componentViewChildren; var childCompChildren = childComponent.componentViewChildren;
expect(childCompChildren.length).toEqual(2); expect(childCompChildren.length).toEqual(2);
expect(DOM.hasClass(childCompChildren[0].domElement, 'child')).toBe(true); expect(DOM.hasClass(childCompChildren[0].nativeElement, 'child')).toBe(true);
expect(DOM.hasClass(childCompChildren[1].domElement, 'child')).toBe(true); expect(DOM.hasClass(childCompChildren[1].nativeElement, 'child')).toBe(true);
var childNested = childCompChildren[0].children; var childNested = childCompChildren[0].children;
expect(childNested.length).toEqual(1); expect(childNested.length).toEqual(1);
expect(DOM.hasClass(childNested[0].domElement, 'childnested')).toBe(true); expect(DOM.hasClass(childNested[0].nativeElement, 'childnested')).toBe(true);
async.done(); async.done();
}); });
@ -193,10 +194,10 @@ export function main() {
var childTestEls = rootTestComponent.queryAll(By.directive(MessageDir)); var childTestEls = rootTestComponent.queryAll(By.directive(MessageDir));
expect(childTestEls.length).toBe(4); expect(childTestEls.length).toBe(4);
expect(DOM.hasClass(childTestEls[0].domElement, 'parent')).toBe(true); expect(DOM.hasClass(childTestEls[0].nativeElement, 'parent')).toBe(true);
expect(DOM.hasClass(childTestEls[1].domElement, 'parentnested')).toBe(true); expect(DOM.hasClass(childTestEls[1].nativeElement, 'parentnested')).toBe(true);
expect(DOM.hasClass(childTestEls[2].domElement, 'child')).toBe(true); expect(DOM.hasClass(childTestEls[2].nativeElement, 'child')).toBe(true);
expect(DOM.hasClass(childTestEls[3].domElement, 'childnested')).toBe(true); expect(DOM.hasClass(childTestEls[3].nativeElement, 'childnested')).toBe(true);
async.done(); async.done();
}); });
})); }));
@ -213,7 +214,7 @@ export function main() {
var childTestEls = parentEl.queryAll(By.directive(MessageDir), Scope.light); var childTestEls = parentEl.queryAll(By.directive(MessageDir), Scope.light);
expect(childTestEls.length).toBe(1); expect(childTestEls.length).toBe(1);
expect(DOM.hasClass(childTestEls[0].domElement, 'parentnested')).toBe(true); expect(DOM.hasClass(childTestEls[0].nativeElement, 'parentnested')).toBe(true);
async.done(); async.done();
}); });
@ -229,8 +230,8 @@ export function main() {
var childTestEls = rootTestComponent.queryAll(By.directive(MessageDir), Scope.view); var childTestEls = rootTestComponent.queryAll(By.directive(MessageDir), Scope.view);
expect(childTestEls.length).toBe(2); expect(childTestEls.length).toBe(2);
expect(DOM.hasClass(childTestEls[0].domElement, 'parent')).toBe(true); expect(DOM.hasClass(childTestEls[0].nativeElement, 'parent')).toBe(true);
expect(DOM.hasClass(childTestEls[1].domElement, 'parentnested')).toBe(true); expect(DOM.hasClass(childTestEls[1].nativeElement, 'parentnested')).toBe(true);
async.done(); async.done();
}); });

View File

@ -15,7 +15,7 @@ import {
TestComponentBuilder, TestComponentBuilder,
By, By,
Scope, Scope,
inspectDomElement inspectNativeElement
} from 'angular2/test_lib'; } from 'angular2/test_lib';
import {global} from 'angular2/src/facade/lang'; import {global} from 'angular2/src/facade/lang';
@ -45,7 +45,7 @@ export function main() {
tcb.overrideTemplate(MyComp, '<div some-dir></div>') tcb.overrideTemplate(MyComp, '<div some-dir></div>')
.createAsync(MyComp) .createAsync(MyComp)
.then((rootTestComponent) => { .then((rootTestComponent) => {
expect(inspectDomElement(rootTestComponent.domElement).componentInstance) expect(inspectNativeElement(rootTestComponent.nativeElement).componentInstance)
.toBeAnInstanceOf(MyComp); .toBeAnInstanceOf(MyComp);
async.done(); async.done();
@ -58,7 +58,7 @@ export function main() {
.createAsync(MyComp) .createAsync(MyComp)
.then((rootTestComponent) => { .then((rootTestComponent) => {
rootTestComponent.destroy(); rootTestComponent.destroy();
expect(inspectDomElement(rootTestComponent.domElement)).toBe(null); expect(inspectNativeElement(rootTestComponent.nativeElement)).toBe(null);
async.done(); async.done();
}); });
@ -71,7 +71,7 @@ export function main() {
tcb.overrideTemplate(MyComp, '') tcb.overrideTemplate(MyComp, '')
.createAsync(MyComp) .createAsync(MyComp)
.then((rootTestComponent) => { .then((rootTestComponent) => {
expect(global['ngProbe'](rootTestComponent.domElement).componentInstance) expect(global['ngProbe'](rootTestComponent.nativeElement).componentInstance)
.toBeAnInstanceOf(MyComp); .toBeAnInstanceOf(MyComp);
async.done(); async.done();

View File

@ -61,7 +61,7 @@ export function main() {
@Directive({selector: '[test-dec]'}) @Directive({selector: '[test-dec]'})
class TestDirective { class TestDirective {
constructor(el: ElementRef) { DOM.addClass(el.domElement, 'compiled'); } constructor(el: ElementRef) { DOM.addClass(el.nativeElement, 'compiled'); }
} }
@Component({selector: 'test-cmp'}) @Component({selector: 'test-cmp'})

View File

@ -46,7 +46,7 @@ export function main() {
inject([AsyncTestCompleter], (async) => { inject([AsyncTestCompleter], (async) => {
var ruler = new Ruler(DOM); var ruler = new Ruler(DOM);
var elRef = <any>new SpyElementRef(); var elRef = <any>new SpyElementRef();
elRef.domElement = DOM.createElement('div'); elRef.nativeElement = DOM.createElement('div');
ruler.measure(elRef).then((rect) => { ruler.measure(elRef).then((rect) => {
// here we are using an element created in a doc fragment so all the measures will come // here we are using an element created in a doc fragment so all the measures will come
// back as 0 // back as 0
@ -61,7 +61,7 @@ export function main() {
@proxy @proxy
@IMPLEMENTS(ElementRef) @IMPLEMENTS(ElementRef)
class SpyElementRef extends SpyObject { class SpyElementRef extends SpyObject {
domElement; nativeElement;
constructor() { super(ElementRef); } constructor() { super(ElementRef); }
noSuchMethod(m) { return super.noSuchMethod(m) } noSuchMethod(m) { return super.noSuchMethod(m) }
} }

View File

@ -62,7 +62,7 @@ export function main() {
tcb.createAsync(ChildComp).then((rootTestComponent) => { tcb.createAsync(ChildComp).then((rootTestComponent) => {
rootTestComponent.detectChanges(); rootTestComponent.detectChanges();
expect(rootTestComponent.domElement).toHaveText('Original Child'); expect(rootTestComponent.nativeElement).toHaveText('Original Child');
async.done(); async.done();
}); });
})); }));
@ -72,11 +72,11 @@ export function main() {
tcb.createAsync(MyIfComp).then((rootTestComponent) => { tcb.createAsync(MyIfComp).then((rootTestComponent) => {
rootTestComponent.detectChanges(); rootTestComponent.detectChanges();
expect(rootTestComponent.domElement).toHaveText('MyIf()'); expect(rootTestComponent.nativeElement).toHaveText('MyIf()');
rootTestComponent.componentInstance.showMore = true; rootTestComponent.componentInstance.showMore = true;
rootTestComponent.detectChanges(); rootTestComponent.detectChanges();
expect(rootTestComponent.domElement).toHaveText('MyIf(More)'); expect(rootTestComponent.nativeElement).toHaveText('MyIf(More)');
async.done(); async.done();
}); });
@ -89,7 +89,7 @@ export function main() {
.createAsync(MockChildComp) .createAsync(MockChildComp)
.then((rootTestComponent) => { .then((rootTestComponent) => {
rootTestComponent.detectChanges(); rootTestComponent.detectChanges();
expect(rootTestComponent.domElement).toHaveText('Mock'); expect(rootTestComponent.nativeElement).toHaveText('Mock');
async.done(); async.done();
}); });
@ -103,7 +103,7 @@ export function main() {
.createAsync(ChildComp) .createAsync(ChildComp)
.then((rootTestComponent) => { .then((rootTestComponent) => {
rootTestComponent.detectChanges(); rootTestComponent.detectChanges();
expect(rootTestComponent.domElement).toHaveText('Modified Child'); expect(rootTestComponent.nativeElement).toHaveText('Modified Child');
async.done(); async.done();
}); });
@ -116,7 +116,7 @@ export function main() {
.createAsync(ParentComp) .createAsync(ParentComp)
.then((rootTestComponent) => { .then((rootTestComponent) => {
rootTestComponent.detectChanges(); rootTestComponent.detectChanges();
expect(rootTestComponent.domElement).toHaveText('Parent(Mock)'); expect(rootTestComponent.nativeElement).toHaveText('Parent(Mock)');
async.done(); async.done();
}); });

View File

@ -1,4 +1,4 @@
import {ElementRef, Component, Directive, View, Injectable} from 'angular2/angular2'; import {ElementRef, Component, Directive, View, Injectable, Renderer} from 'angular2/angular2';
// A service available to the Injector, used by the HelloCmp component. // A service available to the Injector, used by the HelloCmp component.
@Injectable() @Injectable()
@ -12,7 +12,7 @@ class GreetingService {
class RedDec { class RedDec {
// ElementRef is always injectable and it wraps the element on which the // ElementRef is always injectable and it wraps the element on which the
// directive was found by the compiler. // directive was found by the compiler.
constructor(el: ElementRef) { el.domElement.style.color = 'red'; } constructor(el: ElementRef, renderer: Renderer) { renderer.setElementStyle(el, 'color', 'red'); }
} }
// Angular 2.0 supports 2 basic types of directives: // Angular 2.0 supports 2 basic types of directives: