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
4 changes: 3 additions & 1 deletion modules/angular2/src/core/compiler/compiler.js
Original file line number Diff line number Diff line change
Expand Up @@ -90,7 +90,9 @@ export class Compiler {
compileInHost(componentTypeOrBinding:any):Promise<AppProtoView> {
var componentBinding = this._bindDirective(componentTypeOrBinding);
this._assertTypeIsComponent(componentBinding);
return this._renderer.createHostProtoView('host').then( (hostRenderPv) => {

var directiveMetadata = Compiler.buildRenderDirective(componentBinding);
return this._renderer.createHostProtoView(directiveMetadata).then( (hostRenderPv) => {
return this._compileNestedProtoViews(null, hostRenderPv, [componentBinding], true);
});
}
Expand Down
22 changes: 16 additions & 6 deletions modules/angular2/src/render/dom/compiler/compiler.js
Original file line number Diff line number Diff line change
Expand Up @@ -2,8 +2,9 @@ import {Injectable} from 'angular2/di';

import {PromiseWrapper, Promise} from 'angular2/src/facade/async';
import {BaseException} from 'angular2/src/facade/lang';
import {DOM} from 'angular2/src/dom/dom_adapter';

import {ViewDefinition, ProtoViewDto} from '../../api';
import {ViewDefinition, ProtoViewDto, DirectiveMetadata} from '../../api';
import {CompilePipeline} from './compile_pipeline';
import {TemplateLoader} from 'angular2/src/render/dom/compiler/template_loader';
import {CompileStepFactory, DefaultStepFactory} from './compile_step_factory';
Expand Down Expand Up @@ -32,12 +33,21 @@ export class Compiler {
);
}

_compileTemplate(template: ViewDefinition, tplElement):Promise<ProtoViewDto> {
var subTaskPromises = [];
var pipeline = new CompilePipeline(this._stepFactory.createSteps(template, subTaskPromises));
var compileElements;
compileHost(directiveMetadata: DirectiveMetadata):Promise<ProtoViewDto> {
var hostViewDef = new ViewDefinition({
componentId: directiveMetadata.id,
absUrl: null,
template: null,
directives: [directiveMetadata]
});
var element = DOM.createElement(directiveMetadata.selector);
return this._compileTemplate(hostViewDef, element);
}

compileElements = pipeline.process(tplElement, template.componentId);
_compileTemplate(viewDef: ViewDefinition, tplElement):Promise<ProtoViewDto> {
var subTaskPromises = [];
var pipeline = new CompilePipeline(this._stepFactory.createSteps(viewDef, subTaskPromises));
var compileElements = pipeline.process(tplElement, viewDef.componentId);

var protoView = compileElements[0].inheritedProtoView.build();

Expand Down
11 changes: 10 additions & 1 deletion modules/angular2/src/render/dom/compiler/directive_parser.js
Original file line number Diff line number Diff line change
Expand Up @@ -27,11 +27,20 @@ export class DirectiveParser extends CompileStep {
this._selectorMatcher = new SelectorMatcher();
this._directives = directives;
for (var i=0; i<directives.length; i++) {
var selector = CssSelector.parse(directives[i].selector);
var directive = directives[i];
var selector = CssSelector.parse(directive.selector);
this._ensureComponentOnlyHasElementSelector(selector, directive);
this._selectorMatcher.addSelectables(selector, i);
}
}

_ensureComponentOnlyHasElementSelector(selector, directive) {
var isElementSelector = selector.length === 1 && selector[0].isElementSelector();
if (! isElementSelector && directive.type === DirectiveMetadata.COMPONENT_TYPE) {
throw new BaseException(`Component '${directive.id}' can only have an element selector, but had '${directive.selector}'`);
}
}

process(parent:CompileElement, current:CompileElement, control:CompileControl) {
var attrs = current.attrs();
var classList = current.classList();
Expand Down
7 changes: 7 additions & 0 deletions modules/angular2/src/render/dom/compiler/selector.js
Original file line number Diff line number Diff line change
Expand Up @@ -69,6 +69,13 @@ export class CssSelector {
this.notSelector = null;
}

isElementSelector():boolean {
return isPresent(this.element) &&
ListWrapper.isEmpty(this.classNames) &&
ListWrapper.isEmpty(this.attrs) &&
isBlank(this.notSelector);
}

setElement(element:string = null) {
if (isPresent(element)) {
element = element.toLowerCase();
Expand Down
16 changes: 4 additions & 12 deletions modules/angular2/src/render/dom/direct_dom_renderer.js
Original file line number Diff line number Diff line change
Expand Up @@ -11,7 +11,6 @@ import {RenderViewHydrator} from './view/view_hydrator';
import {Compiler} from './compiler/compiler';
import {ShadowDomStrategy} from './shadow_dom/shadow_dom_strategy';
import {ProtoViewBuilder} from './view/proto_view_builder';
import {DOM} from 'angular2/src/dom/dom_adapter';
import {ViewContainer} from './view/view_container';

function _resolveViewContainer(vc:api.RenderViewContainerRef) {
Expand Down Expand Up @@ -80,15 +79,8 @@ export class DirectDomRenderer extends api.Renderer {
this._shadowDomStrategy = shadowDomStrategy;
}

createHostProtoView(componentId):Promise<api.ProtoViewDto> {
var rootElement = DOM.createElement('div');
var hostProtoViewBuilder = new ProtoViewBuilder(rootElement);
var elBinder = hostProtoViewBuilder.bindElement(rootElement, 'root element');
elBinder.setComponentId(componentId);
elBinder.bindDirective(0);

this._shadowDomStrategy.processElement(null, componentId, rootElement);
return PromiseWrapper.resolve(hostProtoViewBuilder.build());
createHostProtoView(directiveMetadata:api.DirectiveMetadata):Promise<api.ProtoViewDto> {
return this._compiler.compileHost(directiveMetadata);
}

createImperativeComponentProtoView(rendererId):Promise<api.ProtoViewDto> {
Expand All @@ -97,10 +89,10 @@ export class DirectDomRenderer extends api.Renderer {
return PromiseWrapper.resolve(protoViewBuilder.build());
}

compile(template:api.ViewDefinition):Promise<api.ProtoViewDto> {
compile(view:api.ViewDefinition):Promise<api.ProtoViewDto> {
// Note: compiler already uses a DirectDomProtoViewRef, so we don't
// need to do anything here
return this._compiler.compile(template);
return this._compiler.compile(view);
}

mergeChildComponentProtoViews(protoViewRef:api.ProtoViewRef, protoViewRefs:List<api.ProtoViewRef>) {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -22,6 +22,8 @@ import {DynamicComponentLoader} from 'angular2/src/core/compiler/dynamic_compone
import {ElementRef} from 'angular2/src/core/compiler/element_injector';
import {If} from 'angular2/src/directives/if';
import {DirectDomRenderer} from 'angular2/src/render/dom/direct_dom_renderer';
import {DOM} from 'angular2/src/dom/dom_adapter';


export function main() {
describe('DynamicComponentLoader', function () {
Expand Down Expand Up @@ -134,6 +136,29 @@ export function main() {
});
});
}));

it('should update host properties', inject([DynamicComponentLoader, TestBed, AsyncTestCompleter],
(loader, tb, async) => {
tb.overrideView(MyComp, new View({
template: '<div><location #loc></location></div>',
directives: [Location]
}));

tb.createView(MyComp).then((view) => {
var location = view.rawView.locals.get("loc");

loader.loadNextToExistingLocation(DynamicallyLoadedWithHostProps, location.elementRef).then(ref => {
ref.instance.id = "new value";

view.detectChanges();

var newlyInsertedElement = DOM.childNodesAsList(view.rootNodes[0])[1];
expect(newlyInsertedElement.id).toEqual("new value")

async.done();
});
});
}));
});

describe('loading into a new location', () => {
Expand Down Expand Up @@ -242,6 +267,19 @@ class DynamicallyLoaded {
class DynamicallyLoaded2 {
}

@Component({
selector: 'dummy',
hostProperties: {'id' : 'id'}
})
@View({template: "DynamicallyLoadedWithHostProps;"})
class DynamicallyLoadedWithHostProps {
id:string;

constructor() {
this.id = "default";
}
}

@Component({
selector: 'location'
})
Expand All @@ -254,7 +292,9 @@ class Location {
}
}

@Component()
@Component({
selector: 'my-comp'
})
@View({
directives: []
})
Expand Down
20 changes: 9 additions & 11 deletions modules/angular2/test/core/compiler/integration_spec.js
Original file line number Diff line number Diff line change
Expand Up @@ -255,20 +255,19 @@ export function main() {
tb.overrideView(MyComp,
new View({
template: '<p [id]="ctxProp"></p>',
directives: [IdComponent]
directives: [IdDir]
}));

tb.createView(MyComp, {context: ctx}).then((view) => {
var idDir = view.rawView.elementInjectors[0].get(IdDir);

ctx.ctxProp = 'some_id';
view.detectChanges();
expect(view.rootNodes[0].id).toEqual('some_id');
expect(view.rootNodes).toHaveText('Matched on id with some_id');
expect(idDir.id).toEqual('some_id');

ctx.ctxProp = 'other_id';
view.detectChanges();
expect(view.rootNodes[0].id).toEqual('other_id');
expect(view.rootNodes).toHaveText('Matched on id with other_id');
expect(idDir.id).toEqual('other_id');

async.done();
});
Expand Down Expand Up @@ -932,7 +931,9 @@ class PushCmpWithRef {
}
}

@Component()
@Component({
selector: 'my-comp'
})
@View({directives: [
]})
class MyComp {
Expand Down Expand Up @@ -1192,14 +1193,11 @@ class DecoratorListeningDomEventNoPrevent {
}
}

@Component({
@Decorator({
selector: '[id]',
properties: {'id': 'id'}
})
@View({
template: '<div>Matched on id with {{id}}</div>'
})
class IdComponent {
class IdDir {
id: string;
}

Expand Down
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
/*
/*
* Runs compiler tests using in-browser DOM adapter.
*/

Expand Down
23 changes: 21 additions & 2 deletions modules/angular2/test/render/dom/compiler/compiler_common_tests.js
Original file line number Diff line number Diff line change
Expand Up @@ -17,7 +17,7 @@ import {Type, isBlank, stringify, isPresent} from 'angular2/src/facade/lang';
import {PromiseWrapper, Promise} from 'angular2/src/facade/async';

import {Compiler, CompilerCache} from 'angular2/src/render/dom/compiler/compiler';
import {ProtoViewDto, ViewDefinition} from 'angular2/src/render/api';
import {ProtoViewDto, ViewDefinition, DirectiveMetadata} from 'angular2/src/render/api';
import {CompileElement} from 'angular2/src/render/dom/compiler/compile_element';
import {CompileStep} from 'angular2/src/render/dom/compiler/compile_step'
import {CompileStepFactory} from 'angular2/src/render/dom/compiler/compile_step_factory';
Expand Down Expand Up @@ -54,6 +54,22 @@ export function runCompilerCommonTests() {
});
}));

it('should run the steps and build the proto view', inject([AsyncTestCompleter], (async) => {
var compiler = createCompiler((parent, current, control) => {
current.inheritedProtoView.bindVariable('b', 'a');
});

var dirMetadata = new DirectiveMetadata({id: 'id', selector: 'CUSTOM', type: DirectiveMetadata.COMPONENT_TYPE});
compiler.compileHost(dirMetadata).then( (protoView) => {
expect(DOM.tagName(protoView.render.delegate.element)).toEqual('CUSTOM')
expect(mockStepFactory.viewDef.directives).toEqual([dirMetadata]);
expect(protoView.variableBindings).toEqual(MapWrapper.createFromStringMap({
'a': 'b'
}));
async.done();
});
}));

it('should use the inline template and compile in sync', inject([AsyncTestCompleter], (async) => {
var compiler = createCompiler(EMPTY_STEP);
compiler.compile(new ViewDefinition({
Expand Down Expand Up @@ -124,11 +140,14 @@ export function runCompilerCommonTests() {
class MockStepFactory extends CompileStepFactory {
steps:List<CompileStep>;
subTaskPromises:List<Promise>;
viewDef:ViewDefinition;

constructor(steps) {
super();
this.steps = steps;
}
createSteps(template, subTaskPromises) {
createSteps(viewDef, subTaskPromises) {
this.viewDef = viewDef;
this.subTaskPromises = subTaskPromises;
ListWrapper.forEach(this.subTaskPromises, (p) => ListWrapper.push(subTaskPromises, p) );
return this.steps;
Expand Down
Loading