Skip to content
Closed
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 1 addition & 1 deletion modules/angular2/src/core/linker/view.ts
Original file line number Diff line number Diff line change
Expand Up @@ -173,7 +173,7 @@ export class AppView implements ChangeDispatcher, RenderEventDispatcher {
logBindingUpdate(b: BindingTarget, value: any): void {
if (b.isDirective() || b.isElementProperty()) {
var elementRef = this.elementRefs[this.elementOffset + b.elementIndex];
this.renderer.setElementAttribute(
this.renderer.setBindingDebugInfo(
elementRef, `${REFLECT_PREFIX}${camelCaseToDashCase(b.name)}`, `${value}`);
}
}
Expand Down
3 changes: 3 additions & 0 deletions modules/angular2/src/core/render/api.ts
Original file line number Diff line number Diff line change
Expand Up @@ -300,6 +300,9 @@ export abstract class Renderer {
abstract setElementAttribute(location: RenderElementRef, attributeName: string,
attributeValue: string);

abstract setBindingDebugInfo(location: RenderElementRef, propertyName: string,
propertyValue: string);

/**
* Sets a (CSS) class on the Element specified via `location`.
*
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -19,7 +19,7 @@ var _allViewsById = new Map<number, AppView>();
var _nextId = 0;

function _setElementId(element, indices: number[]) {
if (isPresent(element)) {
if (isPresent(element) && DOM.isElementNode(element)) {
DOM.setData(element, NG_ID_PROPERTY, indices.join(NG_ID_SEPARATOR));
}
}
Expand Down
30 changes: 26 additions & 4 deletions modules/angular2/src/platform/dom/dom_renderer.ts
Original file line number Diff line number Diff line change
@@ -1,9 +1,9 @@
import {Inject, Injectable, OpaqueToken} from 'angular2/src/core/di';
import {AnimationBuilder} from 'angular2/src/animate/animation_builder';

import {
isPresent,
isBlank,
Json,
RegExpWrapper,
CONST_EXPR,
stringify,
Expand Down Expand Up @@ -40,12 +40,13 @@ import {
DefaultProtoViewRef
} from 'angular2/src/core/render/view';
import {ViewEncapsulation} from 'angular2/src/core/metadata';

// TODO move it once DomAdapter is moved
import {DOM} from 'angular2/src/platform/dom/dom_adapter';
import {camelCaseToDashCase} from './util';

const NAMESPACE_URIS =
CONST_EXPR({'xlink': 'http://www.w3.org/1999/xlink', 'svg': 'http://www.w3.org/2000/svg'});
const TEMPLATE_COMMENT_TEXT = 'template bindings={}';
var TEMPLATE_BINDINGS_EXP = /^template bindings=(.*)$/g;

export abstract class DomRenderer extends Renderer implements NodeFactory<Node> {
abstract registerComponentTemplate(template: RenderComponentTemplate);
Expand Down Expand Up @@ -118,7 +119,7 @@ export abstract class DomRenderer extends Renderer implements NodeFactory<Node>
dehydrateView(viewRef: RenderViewRef) { resolveInternalDomView(viewRef).dehydrate(); }

createTemplateAnchor(attrNameAndValues: string[]): Node {
return this.createElement('script', attrNameAndValues);
return DOM.createComment(TEMPLATE_COMMENT_TEXT);
}
abstract createElement(name: string, attrNameAndValues: string[]): Node;
abstract mergeElement(existing: Node, attrNameAndValues: string[]);
Expand All @@ -145,6 +146,27 @@ export abstract class DomRenderer extends Renderer implements NodeFactory<Node>
}
}

/**
* Used only in debug mode to serialize property changes to comment nodes,
* such as <template> placeholders.
*/
setBindingDebugInfo(location: RenderElementRef, propertyName: string,
propertyValue: string): void {
var view: DefaultRenderView<Node> = resolveInternalDomView(location.renderView);
var element = view.boundElements[location.boundElementIndex];
var dashCasedPropertyName = camelCaseToDashCase(propertyName);
if (DOM.isCommentNode(element)) {
var existingBindings = RegExpWrapper.firstMatch(
TEMPLATE_BINDINGS_EXP, StringWrapper.replaceAll(DOM.getText(element), /\n/g, ''));
var parsedBindings = Json.parse(existingBindings[1]);
parsedBindings[dashCasedPropertyName] = propertyValue;
DOM.setText(element, StringWrapper.replace(TEMPLATE_COMMENT_TEXT, '{}',
Json.stringify(parsedBindings)));
} else {
this.setElementAttribute(location, propertyName, propertyValue);
}
}

setElementClass(location: RenderElementRef, className: string, isAdd: boolean): void {
var view = resolveInternalDomView(location.renderView);
var element = view.boundElements[location.boundElementIndex];
Expand Down
10 changes: 7 additions & 3 deletions modules/angular2/src/platform/server/parse5_adapter.ts
Original file line number Diff line number Diff line change
Expand Up @@ -239,21 +239,25 @@ export class Parse5DomAdapter extends DomAdapter {
treeAdapter.appendChild(el, content.childNodes[i]);
}
}
getText(el): string {
getText(el, isRecursive?: boolean): string {
if (this.isTextNode(el)) {
return el.data;
} else if (this.isCommentNode(el)) {
// In the DOM, comments within an element return an empty string for textContent
// However, comment node instances return the comment content for textContent getter
return isRecursive ? '' : el.data;
} else if (isBlank(el.childNodes) || el.childNodes.length == 0) {
return "";
} else {
var textContent = "";
for (var i = 0; i < el.childNodes.length; i++) {
textContent += this.getText(el.childNodes[i]);
textContent += this.getText(el.childNodes[i], true);
}
return textContent;
}
}
setText(el, value: string) {
if (this.isTextNode(el)) {
if (this.isTextNode(el) || this.isCommentNode(el)) {
el.data = value;
} else {
this.clearNodes(el);
Expand Down
2 changes: 2 additions & 0 deletions modules/angular2/src/web_workers/ui/renderer.ts
Original file line number Diff line number Diff line change
Expand Up @@ -58,6 +58,8 @@ export class MessageBasedRenderer {
bind(this._renderer.setElementProperty, this._renderer));
broker.registerMethod("setElementAttribute", [WebWorkerElementRef, PRIMITIVE, PRIMITIVE],
bind(this._renderer.setElementAttribute, this._renderer));
broker.registerMethod("setBindingDebugInfo", [WebWorkerElementRef, PRIMITIVE, PRIMITIVE],
bind(this._renderer.setBindingDebugInfo, this._renderer));
broker.registerMethod("setElementClass", [WebWorkerElementRef, PRIMITIVE, PRIMITIVE],
bind(this._renderer.setElementClass, this._renderer));
broker.registerMethod("setElementStyle", [WebWorkerElementRef, PRIMITIVE, PRIMITIVE],
Expand Down
11 changes: 11 additions & 0 deletions modules/angular2/src/web_workers/worker/renderer.ts
Original file line number Diff line number Diff line change
Expand Up @@ -196,6 +196,17 @@ export class WebWorkerRenderer implements Renderer {
this._messageBroker.runOnService(args, null);
}

setBindingDebugInfo(location: RenderElementRef, propertyName: string,
propertyValue: string): void {
var fnArgs = [
new FnArg(location, WebWorkerElementRef),
new FnArg(propertyName, null),
new FnArg(propertyValue, null)
];
var args = new UiArguments("setBindingDebugInfo", fnArgs);
this._messageBroker.runOnService(args, null);
}

/**
* Sets a class on an element.
*/
Expand Down
36 changes: 33 additions & 3 deletions modules/angular2/test/core/linker/integration_spec.ts
Original file line number Diff line number Diff line change
Expand Up @@ -89,7 +89,7 @@ import {ViewContainerRef} from 'angular2/src/core/linker/view_container_ref';
import {ViewRef, ViewRef_} from 'angular2/src/core/linker/view_ref';

import {Compiler} from 'angular2/src/core/linker/compiler';
import {ElementRef} from 'angular2/src/core/linker/element_ref';
import {ElementRef, ElementRef_} from 'angular2/src/core/linker/element_ref';
import {TemplateRef} from 'angular2/src/core/linker/template_ref';

import {DomRenderer} from 'angular2/src/platform/dom/dom_renderer';
Expand Down Expand Up @@ -476,6 +476,19 @@ export function main() {
});
}));

it('should use a comment while stamping out `<template>` elements.',
inject([TestComponentBuilder, AsyncTestCompleter], (tcb: TestComponentBuilder, async) => {
tcb.overrideView(MyComp, new ViewMetadata({template: '<template></template>'}))

.createAsync(MyComp)
.then((fixture) => {
var childNodesOfWrapper = DOM.childNodes(fixture.debugElement.nativeElement);
expect(childNodesOfWrapper.length).toBe(1);
expect(DOM.isCommentNode(childNodesOfWrapper[0])).toBe(true);
async.done();
});
}));

it('should support template directives via `template` attribute.',
inject([TestComponentBuilder, AsyncTestCompleter], (tcb: TestComponentBuilder, async) => {
tcb.overrideView(
Expand Down Expand Up @@ -1597,6 +1610,22 @@ export function main() {
async.done();
});
}));

it('should reflect property values on template comments',
inject([TestComponentBuilder, AsyncTestCompleter], (tcb: TestComponentBuilder, async) => {
var tpl = '<template [ngIf]="ctxBoolProp"></template>';
tcb.overrideView(MyComp, new ViewMetadata({template: tpl, directives: [NgIf]}))

.createAsync(MyComp)
.then((fixture) => {
fixture.debugElement.componentInstance.ctxBoolProp = true;
fixture.detectChanges();

expect(DOM.getInnerHTML(fixture.debugElement.nativeElement))
.toContain('"ng\-reflect\-ng\-if"\: "true"');
async.done();
});
}));
});

describe('different proto view storages', () => {
Expand Down Expand Up @@ -1773,6 +1802,7 @@ export function main() {
}));
});


if (DOM.supportsDOMEvents()) {
describe('svg', () => {
it('should support svg elements',
Expand Down Expand Up @@ -1928,8 +1958,8 @@ class PushCmpWithAsyncPipe {
@Injectable()
class MyComp {
ctxProp: string;
ctxNumProp;
ctxBoolProp;
ctxNumProp: number;
ctxBoolProp: boolean;
constructor() {
this.ctxProp = 'initial value';
this.ctxNumProp = 0;
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -56,6 +56,7 @@ import {
ServiceMessageBrokerFactory_
} from 'angular2/src/web_workers/shared/service_message_broker';
import {WebWorkerEventDispatcher} from 'angular2/src/web_workers/worker/event_dispatcher';
import {ChangeDetectorGenConfig} from 'angular2/src/core/change_detection/change_detection';


export function main() {
Expand Down Expand Up @@ -112,6 +113,8 @@ export function main() {
var workerRenderProtoViewStore = new RenderProtoViewRefStore(true);
var workerRenderViewStore = new RenderViewWithFragmentsStore(true);
return [
provide(ChangeDetectorGenConfig,
{useValue: new ChangeDetectorGenConfig(true, true, false)}),
provide(RenderProtoViewRefStore, {useValue: workerRenderProtoViewStore}),
provide(RenderViewWithFragmentsStore, {useValue: workerRenderViewStore}),
provide(Renderer,
Expand Down Expand Up @@ -183,6 +186,22 @@ export function main() {
});
}));

it('should update any template comment property/attributes',
inject([TestComponentBuilder, Renderer, AsyncTestCompleter],
(tcb: TestComponentBuilder, renderer: Renderer, async) => {
var tpl = '<template [ngIf]="ctxBoolProp"></template>';
tcb.overrideView(MyComp, new ViewMetadata({template: tpl, directives: [NgIf]}))

.createAsync(MyComp)
.then((fixture) => {
(<MyComp>fixture.debugElement.componentInstance).ctxBoolProp = true;
fixture.detectChanges();
var el = getRenderElement(fixture.debugElement.elementRef);
expect(DOM.getInnerHTML(el)).toContain('"ng-reflect-ng-if": "true"');
async.done();
});
}));

it('should add and remove fragments',
inject([TestComponentBuilder, AsyncTestCompleter], (tcb: TestComponentBuilder, async) => {
tcb.overrideView(MyComp, new ViewMetadata({
Expand Down Expand Up @@ -232,7 +251,7 @@ export function main() {
class MyComp {
ctxProp: string;
ctxNumProp;
ctxBoolProp;
ctxBoolProp: boolean;
constructor() {
this.ctxProp = 'initial value';
this.ctxNumProp = 0;
Expand Down
2 changes: 1 addition & 1 deletion modules/benchmarks/e2e_test/naive_infinite_scroll_spec.ts
Original file line number Diff line number Diff line change
Expand Up @@ -9,7 +9,7 @@ describe('ng2 naive infinite scroll benchmark', function() {
it('should not throw errors', function() {
browser.get(URL);
var expectedRowCount = 18;
var expectedCellsPerRow = 28;
var expectedCellsPerRow = 27;
var allScrollItems = 'scroll-app #testArea scroll-item';
var cells = `${ allScrollItems } .row *`;
var stageButtons = `${ allScrollItems } .row stage-buttons button`;
Expand Down