Skip to content

Commit c8bdacb

Browse files
committed
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 angular#2712 Last part of angular#2476 Closes angular#2476
1 parent 5c9e53a commit c8bdacb

24 files changed

Lines changed: 115 additions & 134 deletions

modules/angular2/debug.ts

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,2 +1,2 @@
11
export * from './src/debug/debug_element';
2-
export {inspectDomElement, ELEMENT_PROBE_CONFIG} from './src/debug/debug_element_view_listener';
2+
export {inspectNativeElement, ELEMENT_PROBE_CONFIG} from './src/debug/debug_element_view_listener';

modules/angular2/src/core/application.ts

Lines changed: 1 addition & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -56,7 +56,6 @@ import {AppViewListener} from 'angular2/src/core/compiler/view_listener';
5656
import {ProtoViewFactory} from 'angular2/src/core/compiler/proto_view_factory';
5757
import {Renderer, RenderCompiler} from 'angular2/src/render/api';
5858
import {DomRenderer, DOCUMENT_TOKEN} from 'angular2/src/render/dom/dom_renderer';
59-
import {resolveInternalDomView} from 'angular2/src/render/dom/view/view';
6059
import {DefaultDomCompiler} from 'angular2/src/render/dom/compiler/compiler';
6160
import {internalView} from 'angular2/src/core/compiler/view_ref';
6261

@@ -85,10 +84,7 @@ function _injectorBindings(appComponentType): List<Type | Binding | List<any>> {
8584
// TODO(rado): investigate whether to support bindings on root component.
8685
return dynamicComponentLoader.loadAsRoot(appComponentType, null, injector)
8786
.then((componentRef) => {
88-
var domView = resolveInternalDomView(componentRef.hostView.render);
89-
// We need to do this here to ensure that we create Testability and
90-
// it's ready on the window for users.
91-
registry.registerApplication(domView.boundElements[0].element, testability);
87+
registry.registerApplication(componentRef.location.nativeElement, testability);
9288

9389
return componentRef;
9490
});

modules/angular2/src/core/compiler/dynamic_component_loader.ts

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -36,7 +36,7 @@ export class DynamicComponentLoader {
3636
.then(hostProtoViewRef => {
3737
var hostViewRef =
3838
this._viewManager.createRootHostView(hostProtoViewRef, overrideSelector, injector);
39-
var newLocation = new ElementRef(hostViewRef, 0);
39+
var newLocation = this._viewManager.getHostElement(hostViewRef);
4040
var component = this._viewManager.getComponent(newLocation);
4141

4242
var dispose = () => { this._viewManager.destroyRootHostView(hostViewRef); };
@@ -68,7 +68,7 @@ export class DynamicComponentLoader {
6868
var viewContainer = this._viewManager.getViewContainer(location);
6969
var hostViewRef =
7070
viewContainer.create(hostProtoViewRef, viewContainer.length, null, injector);
71-
var newLocation = new ElementRef(hostViewRef, 0);
71+
var newLocation = this._viewManager.getHostElement(hostViewRef);
7272
var component = this._viewManager.getComponent(newLocation);
7373

7474
var dispose = () => {
Lines changed: 9 additions & 28 deletions
Original file line numberDiff line numberDiff line change
@@ -1,41 +1,22 @@
1-
import {DOM} from 'angular2/src/dom/dom_adapter';
2-
import {normalizeBlank, BaseException} from 'angular2/src/facade/lang';
1+
import {BaseException} from 'angular2/src/facade/lang';
32
import {ViewRef} from './view_ref';
4-
import {resolveInternalDomView} from 'angular2/src/render/dom/view/view';
5-
import {RenderViewRef, RenderElementRef} from 'angular2/src/render/api';
3+
import {RenderViewRef, RenderElementRef, Renderer} from 'angular2/src/render/api';
64

75
/**
86
* @exportedAs angular2/view
97
*/
108
export class ElementRef implements RenderElementRef {
11-
constructor(public parentView: ViewRef, public boundElementIndex: number) {}
9+
constructor(public parentView: ViewRef, public boundElementIndex: number,
10+
private _renderer: Renderer) {}
1211

13-
get renderView() { return this.parentView.render; }
12+
get renderView(): RenderViewRef { return this.parentView.render; }
1413
// TODO(tbosch): remove this once Typescript supports declaring interfaces
1514
// that contain getters
16-
set renderView(value: any) { throw new BaseException('Abstract setter'); }
15+
set renderView(viewRef: RenderViewRef) { throw new BaseException('Abstract setter'); }
1716

1817
/**
19-
* Exposes the underlying DOM element.
20-
* (DEPRECATED way of accessing the DOM, replacement coming)
18+
* Exposes the underlying native element.
19+
* Attention: This won't work in a webworker scenario!
2120
*/
22-
// TODO(tbosch): Here we expose the real DOM element.
23-
// We need a more general way to read/write to the DOM element
24-
// via a proper abstraction in the render layer
25-
get domElement() {
26-
return resolveInternalDomView(this.parentView.render)
27-
.boundElements[this.boundElementIndex]
28-
.element;
29-
}
30-
31-
/**
32-
* Gets an attribute from the underlying DOM element.
33-
* (DEPRECATED way of accessing the DOM, replacement coming)
34-
*/
35-
// TODO(tbosch): Here we expose the real DOM element.
36-
// We need a more general way to read/write to the DOM element
37-
// via a proper abstraction in the render layer
38-
getAttribute(name: string): string {
39-
return normalizeBlank(DOM.getAttribute(this.domElement, name));
40-
}
21+
get nativeElement(): any { return this._renderer.getNativeElementSync(this); }
4122
}

modules/angular2/src/core/compiler/view.ts

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -65,7 +65,7 @@ export class AppView implements ChangeDispatcher, EventDispatcher {
6565
this.elementRefs = ListWrapper.createFixedSize(this.proto.elementBinders.length);
6666
this.ref = new ViewRef(this);
6767
for (var i = 0; i < this.elementRefs.length; i++) {
68-
this.elementRefs[i] = new ElementRef(this.ref, i);
68+
this.elementRefs[i] = new ElementRef(this.ref, i, renderer);
6969
}
7070
this.locals = new Locals(null, MapWrapper.clone(protoLocals)); // TODO optimize this
7171
}

modules/angular2/src/core/compiler/view_manager.ts

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -30,6 +30,10 @@ export class AppViewManager {
3030
return hostView.elementInjectors[location.boundElementIndex].getViewContainerRef();
3131
}
3232

33+
getHostElement(hostViewRef: ViewRef): ElementRef {
34+
return internalView(hostViewRef).elementRefs[0];
35+
}
36+
3337
/**
3438
* Returns an ElementRef for the element with the given variable name
3539
* in the component view of the component at the provided ElementRef.

modules/angular2/src/core/compiler/view_manager_utils.ts

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -165,7 +165,7 @@ export class AppViewManagerUtils {
165165
if (isPresent(elementInjector.getDirectiveVariableBindings())) {
166166
MapWrapper.forEach(elementInjector.getDirectiveVariableBindings(), (directiveIndex, name) => {
167167
if (isBlank(directiveIndex)) {
168-
view.locals.set(name, elementInjector.getElementRef().domElement);
168+
view.locals.set(name, elementInjector.getElementRef().nativeElement);
169169
} else {
170170
view.locals.set(name, elementInjector.getDirectiveAtIndex(directiveIndex));
171171
}

modules/angular2/src/debug/debug_element.ts

Lines changed: 3 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -8,8 +8,6 @@ import {AppView} from 'angular2/src/core/compiler/view';
88
import {internalView} from 'angular2/src/core/compiler/view_ref';
99
import {ElementRef} from 'angular2/src/core/compiler/element_ref';
1010

11-
import {resolveInternalDomView} from 'angular2/src/render/dom/view/view';
12-
1311
/**
1412
* @exportedAs angular2/test
1513
*
@@ -35,13 +33,9 @@ export class DebugElement {
3533
return this._elementInjector.getComponent();
3634
}
3735

38-
get domElement(): any {
39-
return resolveInternalDomView(this._parentView.render)
40-
.boundElements[this._boundElementIndex]
41-
.element;
42-
}
36+
get nativeElement(): any { return this.elementRef.nativeElement; }
4337

44-
get elementRef(): ElementRef { return this._elementInjector.getElementRef(); }
38+
get elementRef(): ElementRef { return this._parentView.elementRefs[this._boundElementIndex]; }
4539

4640
getDirectiveInstance(directiveIndex: number): any {
4741
return this._elementInjector.getDirectiveAtIndex(directiveIndex);
@@ -192,7 +186,7 @@ export class By {
192186
static all(): Function { return (debugElement) => true; }
193187

194188
static css(selector: string): Function {
195-
return (debugElement) => { return DOM.elementMatches(debugElement.domElement, selector); };
189+
return (debugElement) => { return DOM.elementMatches(debugElement.nativeElement, selector); };
196190
}
197191
static directive(type: Type): Function {
198192
return (debugElement) => { return debugElement.hasDirective(type); };

modules/angular2/src/debug/debug_element_view_listener.ts

Lines changed: 7 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -10,7 +10,7 @@ import {Injectable, bind, Binding} from 'angular2/di';
1010
import {AppViewListener} from 'angular2/src/core/compiler/view_listener';
1111
import {AppView} from 'angular2/src/core/compiler/view';
1212
import {DOM} from 'angular2/src/dom/dom_adapter';
13-
import {resolveInternalDomView} from 'angular2/src/render/dom/view/view';
13+
import {Renderer} from 'angular2/src/render/api';
1414
import {DebugElement} from './debug_element';
1515

1616
const NG_ID_PROPERTY = 'ngid';
@@ -41,7 +41,7 @@ function _getElementId(element): List<number> {
4141
}
4242
}
4343

44-
export function inspectDomElement(element): DebugElement {
44+
export function inspectNativeElement(element): DebugElement {
4545
var elId = _getElementId(element);
4646
if (isPresent(elId)) {
4747
var view = _allViewsById.get(elId[0]);
@@ -54,15 +54,16 @@ export function inspectDomElement(element): DebugElement {
5454

5555
@Injectable()
5656
export class DebugElementViewListener implements AppViewListener {
57-
constructor() { DOM.setGlobalVar(INSPECT_GLOBAL_NAME, inspectDomElement); }
57+
constructor(private _renderer: Renderer) {
58+
DOM.setGlobalVar(INSPECT_GLOBAL_NAME, inspectNativeElement);
59+
}
5860

5961
viewCreated(view: AppView) {
6062
var viewId = _nextId++;
6163
_allViewsById.set(viewId, view);
6264
_allIdsByView.set(view, viewId);
63-
var renderView = resolveInternalDomView(view.render);
64-
for (var i = 0; i < renderView.boundElements.length; i++) {
65-
_setElementId(renderView.boundElements[i].element, [viewId, i]);
65+
for (var i = 0; i < view.elementRefs.length; i++) {
66+
_setElementId(this._renderer.getNativeElementSync(view.elementRefs[i]), [viewId, i]);
6667
}
6768
}
6869

modules/angular2/src/directives/class.ts

Lines changed: 5 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -2,29 +2,23 @@ import {Directive, onCheck} from 'angular2/annotations';
22
import {ElementRef} from 'angular2/core';
33
import {PipeRegistry} from 'angular2/src/change_detection/pipes/pipe_registry';
44
import {isPresent} from 'angular2/src/facade/lang';
5-
import {DOM} from 'angular2/src/dom/dom_adapter';
5+
import {Renderer} from 'angular2/src/render/api';
66

77
@Directive({selector: '[class]', lifecycle: [onCheck], properties: ['rawClass: class']})
88
export class CSSClass {
9-
_domEl;
109
_pipe;
1110
_rawClass;
1211

13-
constructor(private _pipeRegistry: PipeRegistry, ngEl: ElementRef) {
14-
this._domEl = ngEl.domElement;
15-
}
12+
constructor(private _pipeRegistry: PipeRegistry, private _ngEl: ElementRef,
13+
private _renderer: Renderer) {}
1614

1715
set rawClass(v) {
1816
this._rawClass = v;
1917
this._pipe = this._pipeRegistry.get('keyValDiff', this._rawClass);
2018
}
2119

2220
_toggleClass(className, enabled): void {
23-
if (enabled) {
24-
DOM.addClass(this._domEl, className);
25-
} else {
26-
DOM.removeClass(this._domEl, className);
27-
}
21+
this._renderer.setElementClass(this._ngEl, className, enabled);
2822
}
2923

3024
onCheck() {
@@ -38,7 +32,7 @@ export class CSSClass {
3832
diff.forEachChangedItem((record) => { this._toggleClass(record.key, record.currentValue); });
3933
diff.forEachRemovedItem((record) => {
4034
if (record.previousValue) {
41-
DOM.removeClass(this._domEl, record.key);
35+
this._toggleClass(record.key, false);
4236
}
4337
});
4438
}

0 commit comments

Comments
 (0)